在过去(Java 7和更低版本)中,Java类和接口扮演着不同的角色:用于抽象方法实现的类;用于抽象对象结构的接口。但是,从Java 8开始,接口现在可以使用默认方法定义方法实现。这导致了一个称为“钻石问题”的问题。
具有方法A
的接口execute()
由包含B
的默认实现的接口C
和execute()
扩展。如果某个类随后实现了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
”?
答案 0 :(得分:0)
由于execute()
中有D
的两种实现,因此编译器将不知道要使用哪种实现。换句话说,该程序将无法编译。
重新解决
解决方案D需要创建execute()
的新实现,以便在调用(new D()).execute()
时,编译器直接在execute()
中调用D
而不是尝试(并失败)找出要运行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\nC 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
的方法实现。