How should I have explained the difference between

2019-01-01 07:21发布

In one of my interviews, I have been asked to explain the difference between an Interface and an Abstract class.

Here's my response:

Methods of a Java interface are implicitly abstract and cannot have implementations. A Java abstract class can have instance methods that implements a default behaviour.

Variables declared in a Java interface are by default final. An abstract class may contain non-final variables.

Members of a Java interface are public by default. A Java abstract class can have the usual flavours of class members like private, protected, etc.

A Java interface should be implemented using keyword “implements”; A Java abstract class should be extended using keyword “extends”.

An interface can extend another Java interface only, an abstract class can extend another Java class and implement multiple Java interfaces.

A Java class can implement multiple interfaces but it can extend only one abstract class.

However, the interviewer was not satisfied, and told me that this description represented "bookish knowledge".

He asked me for a more practical response, explaining when I would choose an abstract class over an interface, using practical examples.

Where did I go wrong?

28条回答
初与友歌
2楼-- · 2019-01-01 08:00

Difference between Abstact class and interface

  1. Abstract classes versus interfaces in Java 8
  2. Conceptual Difference:

Interface Default Methods in Java 8

  1. What is Default Method?
  2. ForEach method compilation error solved using Default Method
  3. Default Method and Multiple Inheritance Ambiguity Problems
  4. Important points about java interface default methods:

Java Interface Static Method

  1. Java Interface Static Method, code example, static method vs default method
  2. Important points about java interface static method:

Java Functional Interfaces



Abstract classes versus interfaces in Java 8

Java 8 interface changes include static methods and default methods in interfaces. Prior to Java 8, we could have only method declarations in the interfaces. But from Java 8, we can have default methods and static methods in the interfaces.

After introducing Default Method, it seems that interfaces and abstract classes are same. However, they are still different concept in Java 8.

Abstract class can define constructor. They are more structured and can have a state associated with them. While in contrast, default method can be implemented only in the terms of invoking other interface methods, with no reference to a particular implementation's state. Hence, both use for different purposes and choosing between two really depends on the scenario context.

Conceptual Difference:

Abstract classes are valid for skeletal (i.e. partial) implementations of interfaces but should not exist without a matching interface.

So when abstract classes are effectively reduced to be low-visibility, skeletal implementations of interfaces, can default methods take this away as well? Decidedly: No! Implementing interfaces almost always requires some or all of those class-building tools which default methods lack. And if some interface doesn’t, it is clearly a special case, which should not lead you astray.

Interface Default Methods in Java 8

Java 8 introduces “Default Method” or (Defender methods) new feature, which allows developer to add new methods to the Interfaces without breaking the existing implementation of these Interface. It provides flexibility to allow Interface define implementation which will use as default in the situation where a concrete Class fails to provide an implementation for that method.

Let consider small example to understand how it works:

public interface OldInterface {
    public void existingMethod();
 
    default public void newDefaultMethod() {
        System.out.println("New default method"
               + " is added in interface");
    }
}

The following Class will compile successfully in Java JDK 8,

public class OldInterfaceImpl implements OldInterface {
    public void existingMethod() {
     // existing implementation is here…
    }
}

If you create an instance of OldInterfaceImpl:

OldInterfaceImpl obj = new OldInterfaceImpl ();
// print “New default method add in interface”
obj.newDefaultMethod(); 

Default Method:

Default methods are never final, can not be synchronized and can not override Object’s methods. They are always public, which severely limits the ability to write short and reusable methods.

Default methods can be provided to an Interface without affecting implementing Classes as it includes an implementation. If each added method in an Interface defined with implementation then no implementing Class is affected. An implementing Class can override the default implementation provided by the Interface.

Default methods enable to add new functionality to existing Interfaces without breaking older implementation of these Interfaces.

When we extend an interface that contains a default method, we can perform following,

  1. Not override the default method and will inherit the default method.
  2. Override the default method similar to other methods we override in subclass.
  3. Redeclare default method as abstract, which force subclass to override it.

ForEach method compilation error solved using Default Method

For Java 8, the JDK collections have been extended and forEach method is added to the entire collection (which work in conjunction with lambdas). With conventional way, the code looks like below,

public interface Iterable<T> {
    public void forEach(Consumer<? super T> consumer);
}

Since this result each implementing Class with compile errors therefore, a default method added with a required implementation in order that the existing implementation should not be changed.

The Iterable Interface with the Default method is below,

public interface Iterable<T> {
    public default void forEach(Consumer
                   <? super T> consumer) {
        for (T t : this) {
            consumer.accept(t);
        }
    }
}

The same mechanism has been used to add Stream in JDK Interface without breaking the implementing Classes.


Default Method and Multiple Inheritance Ambiguity Problems

Since java Class can implement multiple Interfaces and each Interface can define default method with same method signature, therefore, the inherited methods can conflict with each other.

Consider below example,

public interface InterfaceA {  
       default void defaultMethod(){  
           System.out.println("Interface A default method");  
    }  
}
 
public interface InterfaceB {
   default void defaultMethod(){
       System.out.println("Interface B default method");
   }
}
 
public class Impl implements InterfaceA, InterfaceB  {
}

The above code will fail to compile with the following error,

java: class Impl inherits unrelated defaults for defaultMethod() from types InterfaceA and InterfaceB

In order to fix this class, we need to provide default method implementation:

public class Impl implements InterfaceA, InterfaceB {
    public void defaultMethod(){
    }
}

Further, if we want to invoke default implementation provided by any of super Interface rather than our own implementation, we can do so as follows,

public class Impl implements InterfaceA, InterfaceB {
    public void defaultMethod(){
        // existing code here..
        InterfaceA.super.defaultMethod();
    }
}

We can choose any default implementation or both as part of our new method.

Important points about java interface default methods:

  1. Java interface default methods will help us in extending interfaces without having the fear of breaking implementation classes.
  2. Java interface default methods has bridge down the differences between interfaces and abstract classes.
  3. Java 8 interface default methods will help us in avoiding utility classes, such as all the Collections class method can be provided in the interfaces itself.
  4. Java interface default methods will help us in removing base implementation classes, we can provide default implementation and the implementation classes can chose which one to override.
  5. One of the major reason for introducing default methods in interfaces is to enhance the Collections API in Java 8 to support lambda expressions.
  6. If any class in the hierarchy has a method with same signature, then default methods become irrelevant. A default method cannot override a method from java.lang.Object. The reasoning is very simple, it’s because Object is the base class for all the java classes. So even if we have Object class methods defined as default methods in interfaces, it will be useless because Object class method will always be used. That’s why to avoid confusion, we can’t have default methods that are overriding Object class methods.
  7. Java interface default methods are also referred to as Defender Methods or Virtual extension methods.

Resource Link:

  1. Interface with default methods vs Abstract class in Java 8
  2. Abstract class versus interface in the JDK 8 era
  3. Interface evolution via virtual extension methods

Java Interface Static Method

Java Interface Static Method, code example, static method vs default method

Java interface static method is similar to default method except that we can’t override them in the implementation classes. This feature helps us in avoiding undesired results incase of poor implementation in implementation classes. Let’s look into this with a simple example.

public interface MyData {

    default void print(String str) {
        if (!isNull(str))
            System.out.println("MyData Print::" + str);
    }

    static boolean isNull(String str) {
        System.out.println("Interface Null Check");

        return str == null ? true : "".equals(str) ? true : false;
    }
}

Now let’s see an implementation class that is having isNull() method with poor implementation.

public class MyDataImpl implements MyData {

    public boolean isNull(String str) {
        System.out.println("Impl Null Check");

        return str == null ? true : false;
    }

    public static void main(String args[]){
        MyDataImpl obj = new MyDataImpl();
        obj.print("");
        obj.isNull("abc");
    }
}

Note that isNull(String str) is a simple class method, it’s not overriding the interface method. For example, if we will add @Override annotation to the isNull() method, it will result in compiler error.

Now when we will run the application, we get following output.

Interface Null Check

Impl Null Check

If we make the interface method from static to default, we will get following output.

Impl Null Check

MyData Print::

Impl Null Check

Java interface static method is visible to interface methods only, if we remove the isNull() method from the MyDataImpl class, we won’t be able to use it for the MyDataImpl object. However like other static methods, we can use interface static methods using class name. For example, a valid statement will be:

boolean result = MyData.isNull("abc");

Important points about java interface static method:

  1. Java interface static method is part of interface, we can’t use it for implementation class objects.
  2. Java interface static methods are good for providing utility methods, for example null check, collection sorting etc.
  3. Java interface static method helps us in providing security by not allowing implementation classes to override them.
  4. We can’t define interface static method for Object class methods, we will get compiler error as “This static method cannot hide the instance method from Object”. This is because it’s not allowed in java, since Object is the base class for all the classes and we can’t have one class level static method and another instance method with same signature.
  5. We can use java interface static methods to remove utility classes such as Collections and move all of it’s static methods to the corresponding interface, that would be easy to find and use.

Java Functional Interfaces

Before I conclude the post, I would like to provide a brief introduction to Functional interfaces. An interface with exactly one abstract method is known as Functional Interface.

A new annotation @FunctionalInterface has been introduced to mark an interface as Functional Interface. @FunctionalInterface annotation is a facility to avoid accidental addition of abstract methods in the functional interfaces. It’s optional but good practice to use it.

Functional interfaces are long awaited and much sought out feature of Java 8 because it enables us to use lambda expressions to instantiate them. A new package java.util.function with bunch of functional interfaces are added to provide target types for lambda expressions and method references. We will look into functional interfaces and lambda expressions in the future posts.

Resource Location:

  1. Java 8 Interface Changes – static method, default method
查看更多
余生请多指教
3楼-- · 2019-01-01 08:02

Yes, your responses were technically correct but where you went wrong was not showing them you understand the upsides and downsides of choosing one over the other. Additionally, they were probably concerned/freaked out about compatibility of their codebase with upgrades in the future. This type of response may have helped (in addition to what you said):

"Choosing an Abstract Class over an Interface Class depends on what we project the future of the code will be.

Abstract classes allow better forward-compatibility because you can continue adding behavior to an Abstract Class well into the future without breaking your existing code --> this is not possible with an Interface Class.

On the other hand, Interface Classes are more flexible than Abstract Classes. This is because they can implement multiple interfaces. The thing is Java does not have multiple inheritances so using abstract classes won't let you use any other class hierarchy structure...

So, in the end a good general rule of thumb is: Prefer using Interface Classes when there are no existing/default implementations in your codebase. And, use Abstract Classes to preserve compatibility if you know you will be updating your class in the future."

Good luck on your next interview!

查看更多
萌妹纸的霸气范
4楼-- · 2019-01-01 08:03

All your statements are valid except your first statement (after the Java 8 release):

Methods of a Java interface are implicitly abstract and cannot have implementations

From the documentation page:

An interface is a reference type, similar to a class, that can contain only constants, method signatures, default methods, static methods,and nested types

Method bodies exist only for default methods and static methods.

Default methods:

An interface can have default methods, but are different than abstract methods in abstract classes.

Default methods enable you to add new functionality to the interfaces of your libraries and ensure binary compatibility with code written for older versions of those interfaces.

When you extend an interface that contains a default method, you can do the following:

  1. Not mention the default method at all, which lets your extended interface inherit the default method.
  2. Redeclare the default method, which makes it abstract.
  3. Redefine the default method, which overrides it.

Static Methods:

In addition to default methods, you can define static methods in interfaces. (A static method is a method that is associated with the class in which it is defined rather than with any object. Every instance of the class shares its static methods.)

This makes it easier for you to organize helper methods in your libraries;

Example code from documentation page about interface having static and default methods.

import java.time.*;

public interface TimeClient {
    void setTime(int hour, int minute, int second);
    void setDate(int day, int month, int year);
    void setDateAndTime(int day, int month, int year,
                               int hour, int minute, int second);
    LocalDateTime getLocalDateTime();

    static ZoneId getZoneId (String zoneString) {
        try {
            return ZoneId.of(zoneString);
        } catch (DateTimeException e) {
            System.err.println("Invalid time zone: " + zoneString +
                "; using default time zone instead.");
            return ZoneId.systemDefault();
        }
    }

    default ZonedDateTime getZonedDateTime(String zoneString) {
        return ZonedDateTime.of(getLocalDateTime(), getZoneId(zoneString));
    }
}

Use the below guidelines to chose whether to use an interface or abstract class.

Interface:

  1. To define a contract ( preferably stateless - I mean no variables )
  2. To link unrelated classes with has a capabilities.
  3. To declare public constant variables (immutable state)

Abstract class:

  1. Share code among several closely related classes. It establishes is a relation.

  2. Share common state among related classes ( state can be modified in concrete classes)

Related posts:

Interface vs Abstract Class (general OO)

Implements vs extends: When to use? What's the difference?

By going through these examples, you can understand that

Unrelated classes can have capabilities through interface but related classes change the behaviour through extension of base classes.

查看更多
千与千寻千般痛.
5楼-- · 2019-01-01 08:04

An interface is a "contract" where the class that implements the contract promises to implement the methods. An example where I had to write an interface instead of a class was when I was upgrading a game from 2D to 3D. I had to create an interface to share classes between the 2D and the 3D version of the game.

package adventure;
import java.awt.*;
public interface Playable {
    public void playSound(String s);
    public Image loadPicture(String s);    
}

Then I can implement the methods based on the environment, while still being able to call those methods from an object that doesn't know which version of the game that is loading.

public class Adventure extends JFrame implements Playable

public class Dungeon3D extends SimpleApplication implements Playable

public class Main extends SimpleApplication implements AnimEventListener, ActionListener, Playable

Typically, in the gameworld, the world can be an abstract class that performs methods on the game:

public abstract class World...

    public Playable owner;

    public Playable getOwner() {
        return owner;
    }

    public void setOwner(Playable owner) {
        this.owner = owner;
    }
查看更多
闭嘴吧你
6楼-- · 2019-01-01 08:04

From what I understand, an Interface, which is comprised of final variables and methods with no implementations, is implemented by a class to obtain a group of methods or methods that are related to each other. On the other hand, an abstract class, which can contain non-final variables and methods with implementations, is usually used as a guide or as a superclass from which all related or similar classes inherits from. In other words, an abstract class contains all the methods/variables that are shared by all its subclasses.

查看更多
余欢
7楼-- · 2019-01-01 08:04

your answer is right but the interviewer needs you to differentiate according to software engineering perspective not according to the details of Java.

Simple words:

An Interface is like the interface of a shop anything that is shown on it should be there in the shop, so any method in the Interface must be there implemented in the concrete class. Now what if some classes share some exact methods and varies in others. Suppose the Interface is about a shop that contains two things and suppose we have two shops both contain sport equipment but one has clothes extra and the other has shoes extra. So what you do is making an abstract class for Sport that implements the Sports method and leave the other method unimplemented. Abstract class here means that this shop doesn't exist itself but it is the base for other classes/shops. This way you are organising the code, avoiding errors of replicating the code, unifying the code, and ensuring re-usability by some other class.

查看更多
登录 后发表回答