Java 8中的抽象类和接口有什么区别?

时间:2014-03-23 13:25:19

标签: java interface abstract-class java-8 diamond-problem

在Java中,抽象类和接口之间曾经有一个微妙但重要的区别:default implementations。抽象类可以拥有它们,接口却不能。 Java 8虽然引入了接口的默认实现,但这意味着它不再是接口和抽象类之间的关键区别。

那是什么?

尽我所知,唯一剩下的区别(除了可能是引擎效率之外的东西)是抽象类遵循传统的Java单继承,而接口可以有多重继承(或者如果你愿意,可以使用多个实现) )。这引出了另一个问题 -

新的Java 8接口如何避免diamond Problem

5 个答案:

答案 0 :(得分:68)

接口不能具有与之关联的状态。

抽象类可以具有与之关联的状态。

此外,无需实现接口中的默认方法。因此,通过这种方式,它不会破坏已有的代码,因为当接口确实接收到更新时,实现类不需要实现它。
因此,您可能会获得次优代码,但如果您想拥有更优化的代码,那么您的工作就是覆盖默认实现。

最后,如果发生钻石问题,编译器会发出警告,需要选择你想要实现的接口。

要了解有关钻石问题的更多信息,请考虑以下代码:

interface A {
    void method();
}

interface B extends A {
    @Override
    default void method() {
        System.out.println("B");
    }
}

interface C extends A { 
    @Override
    default void method() {
        System.out.println("C");
    }
}

interface D extends B, C {

}

这里我在interface D extends B, C上得到编译器错误,即:

interface D inherits unrelated defaults for method() form types B and C

修复方法是:

interface D extends B, C {
    @Override
    default void method() {
        B.super.method();
    }
}

如果我想从method()继承B 如果Dclass,则同样适用。

要更多地了解Java 8中接口和抽象类之间的区别,请考虑以下Team

interface Player {

}

interface Team {
    void addPlayer(Player player);
}

理论上,您可以提供addPlayer的默认实施,以便您可以添加玩家,例如玩家列表。
但是等等......? 如何存储玩家列表?
答案是,即使您有默认实现,也无法在界面中执行此操作。

答案 1 :(得分:17)

已经有一些非常详细的答案,但它们似乎缺少一点,我至少认为这是完全拥有抽象类 的少数理由之一:

抽象类可以包含受保护的成员(以及具有默认可见性的成员)。接口中的方法隐式 public

答案 2 :(得分:8)

钻石问题的定义含糊不清。多重继承可能会出现各种问题。幸运的是,大多数都可以在编译时轻松检测到,编程语言支持简单的解决方案来解决这些问题。大多数问题甚至不是钻石问题特有的。例如,如果没有钻石

,也可能会发生冲突的方法定义
interface Bar {
    default int test() { return 42; }
}
interface Baz {
    default int test() { return 6 * 9; }
}
class Foo implements Bar, Baz { }

diamond 的具体问题是包含独占的问题。如果您有一个类型层次结构,其中 B C 派生自 A ,而 D 派生自 B C ,那么问题是:

  • D a B *和* a C (即一种 A )或< / LI>
  • D a B *或* a C (即两种类型的 A )。

好吧,在Java 8中, A 类型必须是接口。所以没有区别,因为 interfaces 没有状态。无关紧要, interfaces 可以定义默认方法,因为它们也没有状态。他们可以调用直接访问状态的方法。但是,这些方法总是基于单继承实现。

答案 3 :(得分:5)

现在接口可以包含可执行代码,接口会接管许多抽象类的用例。但抽象类仍然可以有成员变量,而接口则不能。

当两个接口为具有相同签名的同一方法提供默认实现时,简单地不允许类实现两个接口,从而避免了钻石问题。

答案 4 :(得分:4)

  

Java 8虽然引入了接口的默认实现,但这意味着它不再是接口和抽象类之间的关键区别。

仍然存在一些更为重要的差异。请参阅这篇文章:

Interface with default methods vs Abstract class in Java 8

  

新的Java 8接口如何避免钻石问题?

案例1: 您正在实现两个具有相同default方法的接口,您必须解决实现clas中的冲突 s

interface interfaceA{
    default public void foo(){
        System.out.println("InterfaceA foo");
    }
}
interface interfaceB{
    default public void foo(){
        System.out.println("InterfaceB foo");
    }
}
public class DiamondExample implements interfaceA,interfaceB{
    public void foo(){
        interfaceA.super.foo();
    }
    public static void main(String args[]){
        new DiamondExample().foo();
    }
} 

以上示例产生以下输出:

InterfaceA foo

案例2: 您正在扩展基类并使用默认方法实现接口。编译器为您解决钻石问题,您不必像在第一个示例中那样解决它。

interface interfaceA{
    default public void foo(){
        System.out.println("InterfaceA foo");
    }
}

class DiamondBase {
    public void foo(){
        System.out.println("Diamond base foo");
    }
}

public class DiamondExample extends DiamondBase implements interfaceA{

    public static void main(String args[]){
        new DiamondExample().foo();
    }
}

以上示例产生以下输出:

Diamond base foo