在过去(Java 7及更早版本(,Java类和接口扮演不同的角色:用于抽象方法实现的类;用于抽象对象结构的接口。但是,从 Java 8 开始,接口现在可以使用默认方法定义方法实现。这导致了一个被称为"钻石问题"的问题。
使用方法execute()
A
的接口由包含execute()
的默认实现的接口B
和C
进行扩展。如果一个类然后实现B
和C
,则应该运行execute()
的默认实现是模糊的。
interface A {
public void execute();
}
interface B extends A {
default void execute() { System.out.println("B called"); }
}
interface C extends A {
default void execute() { System.out.println("C called"); }
}
class D implements B, C {
}
给定上面的类定义,当执行(new D()).execute()
时,将打印什么(如果有的话(:"B called
"或"C called
"?
由于D
中有两个execute()
实现,编译器将不知道使用哪个实现。换句话说,该程序将无法编译。
决议
解决方案是 D 需要创建一个新的execute()
实现,这样当调用(new D()).execute()
时,编译器直接调用D
中的execute()
,而不是尝试(并失败(找出要从B
或C
中运行哪个实现。
class D implements B, C { // D does not need to implement A, since B and C already do
@Override
public void execute() { // new implementation defined in A
B.super.execute(); // calls execute() defined by B
C.super.execute(); // calls execute() defined by C
}
}
在此示例中,(new D()).execute()
将打印 -
B called
C called
笔记
如果B
和C
都是类,则D
不能作为B
和C
的子类存在,因为 Java 不允许多重继承。但是,如果B
异或C
是类,则D
不需要重新实现execute()
,因为它是在父类中可扩展定义的。
interface B extends A {
default void execute() { System.out.println("B called"); }
}
class C implements A {
public void execute() { System.out.println("C called"); }
}
class D extends C implements B {
// Will compile correctly since C provides the implementation for execute()
}
在此示例中,(new D()).execute()
将打印"C called
"。
D
扩展C
因此将使用C
的方法实现(如果未重写(。