我应该如何解释接口和抽象类之间的区别?

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

这是我的回应:

Java 接口的方法隐式抽象,不能有实现。Java 抽象类可以具有实现默认行为的实例方法。

默认情况下,在 Java 接口中声明的变量是最终变量。抽象类可能包含非最终变量。

默认情况下,Java 接口的成员是公共的。Java抽象类可以具有类成员的通常风格,如私有,受保护等。

Java接口应该使用关键字“implements”来实现;Java 抽象类应使用关键字“extends”进行扩展。

一个接口只能扩展另一个 Java 接口,抽象类可以扩展另一个 Java 类并实现多个 Java 接口。

Java 类可以实现多个接口,但它只能扩展一个抽象类。

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

他要求我提供更实际的回答,使用实际示例解释我何时会选择一个抽象类而不是接口

我哪里做错了?


答案 1

我先举个例子:

public interface LoginAuth{
   public String encryptPassword(String pass);
   public void checkDBforUser();
}

假设您的应用程序中有 3 个数据库。然后,该数据库的每个实现都需要定义上述2种方法:

public class DBMySQL implements LoginAuth{
          // Needs to implement both methods
}
public class DBOracle implements LoginAuth{
          // Needs to implement both methods
}
public class DBAbc implements LoginAuth{
          // Needs to implement both methods
}

但是,如果不是依赖于数据库,并且每个类都是相同的呢?那么上述方法就不是一个好方法了。encryptPassword()

相反,请考虑以下方法:

public abstract class LoginAuth{
   public String encryptPassword(String pass){
            // Implement the same default behavior here 
            // that is shared by all subclasses.
   }

   // Each subclass needs to provide their own implementation of this only:
   public abstract void checkDBforUser();
}

现在,在每个子类中,我们只需要实现一个方法 - 依赖于数据库的方法。


答案 2

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

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

  1. 接口是规则(规则,因为您必须为它们提供无法忽略或避免的实现,以便像规则一样强加它们),它可以作为软件开发中各个团队之间的共同理解文档。

  2. 接口给出了要做什么的想法,而不是如何完成。因此,实现完全依赖于开发人员遵循给定的规则(意味着给定的方法签名)。

  3. 抽象类可以包含抽象声明和/或具体实现。

  4. 抽象声明就像要遵循的规则,具体的实现就像指南(你可以按原样使用它,也可以通过重写并给出你自己的实现来忽略它)。

  5. 此外,哪些具有相同签名的方法可能会在不同的上下文中更改行为,这些方法作为接口声明作为规则提供,以便在不同的上下文中相应地实现。

编辑:Java 8 有助于在接口中定义默认和静态方法。

public interface SomeInterfaceOne {

    void usualAbstractMethod(String inputString);

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

现在,当一个类将实现SomeInterface时,它不是必须为接口的默认方法提供实现。

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

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() 方法提供实现,否则编译器将抛出编译时错误。