解决 Java 接口钻石问题



在过去(Java 7及更早版本(,Java类和接口扮演不同的角色:用于抽象方法实现的类;用于抽象对象结构的接口。但是,从 Java 8 开始,接口现在可以使用默认方法定义方法实现。这导致了一个被称为"钻石问题"的问题。

使用方法execute()A的接口由包含execute()的默认实现的接口BC进行扩展。如果一个类然后实现BC,则应该运行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(),而不是尝试(并失败(找出要从BC中运行哪个实现。

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

笔记

如果BC都是类,则D不能作为BC的子类存在,因为 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的方法实现(如果未重写(。

最新更新