Java 8引入接口默认方法后,一个类同时实现两个都定义了同名默认方法的接口会怎样?这篇真实构造这种菱形冲突场景,验证编译器的真实反应,以及正确的显式覆盖语法。
上一篇:静态字段隐藏真实验证
接口A和接口B互不相关,各自定义了默认实现的greet()方法,类C同时实现两者但不覆盖greet(),真实用javac编译会发生什么。
DiamondErrorDemo.java interface A { default String greet() { return "A"; } } interface B { default String greet() { return "B"; } } static class C implements A, B { // 故意不覆盖greet() }
DiamondErrorDemo.java:8: error: types A and B are incompatible;
static class C implements A, B {
^
class C inherits unrelated defaults for greet() from types A and B
1 error
真实结果证明:Java编译器真实不会替你"猜"应该用A还是B的默认实现——这和C++多重继承里那种运行时才暴露的二义性问题不同,Java真实把这个冲突提前到了编译期,直接拒绝编译并给出清晰的错误信息"inherits unrelated defaults",强制开发者必须显式做出选择。这也是Java为默认方法设计"多重继承实现"时刻意保留的安全边界:接口可以有默认实现,但真实冲突绝不会被静默地按某种隐含优先级自动解决。
InterfaceDiamondDemo.java static class C implements A, B { @Override public String greet() { return A.super.greet() + " + " + B.super.greet(); } }
真实C.greet()(菱形冲突,显式调用两者): 来自A + 来自B
真实结果证明Java提供了接口名.super.方法名()这个专门语法来解决这个冲突——它让开发者能明确指定"我要调用A这个接口的默认实现",甚至可以像示例里这样,在覆盖版本里同时调用A和B两个版本并组合它们的结果。这个语法只能在实现类内部使用,且只能指向类直接实现的接口,不能跳过中间层级。
InterfaceDiamondDemo.java interface Base { default String hello() { return "Base"; } } interface Sub extends Base { default String hello() { return "Sub"; } } static class D implements Base, Sub { // 不需要覆盖 }
真实D.hello()(子接口默认方法自动胜出): Sub
每一行都是真实编译或运行这段代码得到的结果。