在我的一次采访中,我被要求解释接口类和抽象类之间的区别。

以下是我的回答:

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.

然而,面试官并不满意,他告诉我这种描述代表了“书本知识”。

他让我给出一个更实际的回答,用实际的例子解释我什么时候会选择抽象类而不是接口。

我哪里错了?


当前回答

在Java中选择接口是为了避免多重继承中的菱形问题。

如果你想让你所有的方法都由你的客户端实现,你可以选择接口。这意味着你要抽象地设计整个应用程序。

如果您已经知道它们的共同点,那么您就可以选择抽象类。例如,取一个抽象类Car。在更高的级别上实现常见的car方法,如calculateRPM()。这是一种常见的方法,你让客户端实现他自己的行为,比如 calculateMaxSpeed()等。也许你会举几个你在日常工作中遇到的真实例子来解释。

其他回答

根据我的理解和我的做法,

接口就像一个规范/契约,任何实现接口类的类都必须实现抽象类中定义的所有方法(除了默认方法(在Java 8中引入))

然而,当我知道类的一些方法需要实现时,我定义了一个类抽象,而有些方法我仍然不知道实现是什么(我们可能知道函数签名,但不知道实现)。我这样做是为了在开发的后期,当我知道如何实现这些方法时,我可以扩展这个抽象类并实现这些方法。

注意:接口方法中不能有函数体,除非该方法是静态的或默认的。

这个世界上没有什么是完美的。他们可能期待的是更实际的方法。

但在你解释之后,你可以用稍微不同的方法添加这些行。

Interfaces are rules (rules because you must give an implementation to them that you can't ignore or avoid, so that they are imposed like rules) which works as a common understanding document among various teams in software development. Interfaces give the idea what is to be done but not how it will be done. So implementation completely depends on developer by following the given rules (means given signature of methods). Abstract classes may contain abstract declarations, concrete implementations, or both. Abstract declarations are like rules to be followed and concrete implementations are like guidelines (you can use it as it is or you can ignore it by overriding and giving your own implementation to it). Moreover which methods with same signature may change the behaviour in different context are provided as interface declarations as rules to implement accordingly in different contexts.

编辑:Java 8简化了在接口中定义默认方法和静态方法。

public interface SomeInterfaceOne {

    void usualAbstractMethod(String inputString);

    default void defaultMethod(String inputString){
        System.out.println("Inside SomeInterfaceOne defaultMethod::"+inputString);
    }
}

现在,当一个类将实现SomeInterface时,并不强制为interface的默认方法提供实现。

如果我们有另一个具有以下方法的接口:

public interface SomeInterfaceTwo {

    void usualAbstractMethod(String inputString);

    default void defaultMethod(String inputString){
        System.out.println("Inside SomeInterfaceTwo defaultMethod::"+inputString);
    }

}

Java不允许扩展多个类,因为这会导致“钻石问题”,即编译器无法决定使用哪个超类方法。如果使用默认方法,接口也会出现菱形问题。因为如果一个类同时实现这两个

SomeInterfaceOne and SomeInterfaceTwo

并且没有实现常见的默认方法,编译器不能决定选择哪一个。 为了避免这个问题,在java 8中必须实现不同接口的通用缺省方法。如果任何类实现了上述两个接口,它必须提供defaultMethod()方法的实现,否则编译器将抛出编译时错误。

抽象类不是纯粹的抽象,因为它是具体方法(已实现方法)和未实现方法的集合。 但 接口是纯抽象的,因为只有未实现的方法,没有具体的方法。

为什么是抽象类?

如果用户想为所有对象编写通用功能。 抽象类是未来重新实现的最佳选择,可以在不影响最终用户的情况下增加更多的功能。

为什么接口?

如果用户想要编写不同的功能,那将是对象上的不同功能。 一旦接口发布,如果不需要修改需求,接口是最好的选择。

接口是一个“契约”,其中实现契约的类承诺实现方法。举个例子,当我将一款游戏从2D升级到3D时,我不得不编写一个界面而不是类。我必须创建一个界面来共享2D和3D版本的游戏类别。

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

然后我可以实现基于环境的方法,同时仍然能够从一个不知道正在加载的游戏版本的对象调用这些方法。

公共类Adventure扩展了JFrame实现了Playable

公共类Dungeon3D扩展了SimpleApplication实现的Playable

公共类Main扩展了SimpleApplication实现了AnimEventListener ActionListener,播放

通常,在游戏世界中,世界可以是一个抽象类,在游戏中执行方法:

public abstract class World...

    public Playable owner;

    public Playable getOwner() {
        return owner;
    }

    public void setOwner(Playable owner) {
        this.owner = owner;
    }

接口是纯粹抽象的。我们在接口中没有任何实现代码。

抽象类包含方法及其实现。

点击这里观看接口和抽象类教程