解决Java接口钻石问题

时间:2018-08-23 15:30:09

标签: java interface diamond-problem

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

具有方法A的接口execute()由包含B的默认实现的接口Cexecute()扩展。如果某个类随后实现了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”?

1 个答案:

答案 0 :(得分:0)

由于execute()中有D的两种实现,因此编译器将不知道要使用哪种实现。换句话说,该程序将无法编译。

重新解决

解决方案D需要创建execute()的新实现,以便在调用(new D()).execute()时,编译器直接在execute()中调用D而不是尝试(并失败)找出要运行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\nC called”。

注释

如果BC都是类,则D不能作为BC的子代存在,因为Java不允许多重继承。但是,如果BC是类,则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的方法实现。