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

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

那么这是什么呢?

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

新的Java 8接口如何避免菱形问题


答案 1

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

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

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

最后,如果发生菱形问题,编译器会警告您,您将需要选择要实现的接口。

若要显示有关菱形问题的详细信息,请考虑以下代码:

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()BDclass

为了进一步说明Java 8中接口和抽象类之间的区别,请考虑以下几点:Team

interface Player {

}

interface Team {
    void addPlayer(Player player);
}

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


答案 2

有一些非常详细的答案,但它们似乎遗漏了一点,我至少认为这是拥有抽象类的极少数理由之一:

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