接口不能有与之关联的状态。
抽象类可以有与之关联的状态。
此外,接口中的默认方法不需要被实现。这样,它就不会破坏已经存在的代码,因为尽管接口接收到更新,但实现类并不需要实现它。
因此,你可能会得到次优的代码,但如果你想要更优化的代码,那么你的任务就是重写默认实现。
最后,在出现“钻石问题”时,编译器将会警告你,你需要选择你想要实现的接口。
为了更好地展示“钻石问题”,请考虑以下代码:
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();
}
}
如果我想要继承B
中的method()
方法,也是同样的道理。
如果D
是一个class
,情况也是一样的。
为了更好地展示Java 8中接口和抽象类之间的区别,考虑以下Team
案例:
interface Player {
}
interface Team {
void addPlayer(Player player);
}
从理论上讲,您可以提供addPlayer
的默认实现,以便将玩家添加到例如玩家列表中。
但是等等...?
我该如何存储玩家列表呢?
答案是,您不能在接口中这样做,即使您有可用的默认实现。
一些非常详细的答案已经给出,但它们似乎缺少我至少认为是拥有抽象类的极少数正当理由之一的一个要点:
抽象类可以拥有受保护成员(以及默认可见性的成员)。接口中的方法隐式地是公共的。
钻石问题的定义比较模糊。在多重继承时,可能会出现各种问题。幸运的是,大部分问题都可以在编译时轻松检测到,并且编程语言支持简单的解决方案来避免这些问题。这些问题大多数甚至与钻石问题无关。例如,方法定义的冲突也可能在没有钻石的情况下出现:
interface Bar {
default int test() { return 42; }
}
interface Baz {
default int test() { return 6 * 9; }
}
class Foo implements Bar, Baz { }
现在接口可以包含可执行代码,很多抽象类的用例都被接口取代了。但是抽象类仍然可以拥有成员变量,而接口则不行。
钻石问题可以通过简单地不允许一个类实现两个接口来避免,当这两个接口提供相同签名的默认实现时。
default
方法的接口,您必须在您的实现类中解决冲突。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
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