Java菱形继承下调用间接继承接口默认实现编译报错
问题场景
定义了4个类型,出现接口默认方法菱形继承的编译问题,相关代码如下:
public interface Foo<T> { ... default boolean isEmpty() { return false; // 虚拟示例值,实际实现与本问题无关 } } public interface CharSequence { //java.lang.CharSequence ... default boolean isEmpty() { return true; // 虚拟示例值,实际实现与本问题无关 } } public abstract class Bar<T> implements Foo<T> { ... } public final class BarImpl extends Bar<Character> implements CharSequence { // 典型菱形继承问题 ... @Override public boolean isEmpty() { // 需重写该方法解决菱形继承冲突 return Foo.super.isEmpty(); // 编译错误:作用域内不存在可访问的Foo<T>类型闭包实例 return Bar.super.isEmpty(); // 编译错误:作用域内不存在可访问的Bar<T>类型闭包实例 return CharSequence.super.isEmpty(); // 可正常编译 } }
核心疑问:为什么无法访问通过继承Bar类间接获得的、来自Foo接口的isEmpty默认实现?
原因说明
这是Java语言规范对接口默认方法调用、继承优先级的明确规定导致的,核心规则如下:
- 类继承的方法优先级永远高于接口默认方法
只要方法存在于类的继承链上(哪怕这个方法最初是接口的默认方法,只是被上层类继承了没有重写),它的优先级就会高于所有接口的同名同签名默认方法,同时会屏蔽下层子类直接用接口名.super.方法名()语法调用该接口默认方法的权限。
在BarImpl的视角里,Foo接口的isEmpty不是自己直接实现获得的默认方法,是通过父类Bar继承来的、属于类层级的方法,因此不满足Foo.super.isEmpty()的调用前提——这个语法仅允许调用当前类直接实现、且未被类层级屏蔽的接口默认方法,所以这行代码会编译报错。 类名.super.方法名()语法仅能查找该类自身声明或它的直接父类的方法
写Bar.super.isEmpty()的时候,编译器会去查找Bar的直接父类(这里是Object类)中的isEmpty方法,Object类根本不存在该方法,自然会编译报错。虽然Bar从Foo接口继承了isEmpty默认方法,但Bar自身没有声明这个方法的实现,它的直接父类也没有这个方法,所以通过Bar.super找不到目标方法。- 直接实现的接口默认方法可以正常调用super
CharSequence是BarImpl直接用implements关键字声明实现的接口,它的isEmpty默认方法没有被类继承链完全屏蔽(因为类继承链上的同名方法和它刚好构成菱形冲突,编译器强制要求重写),所以CharSequence.super.isEmpty()符合语法要求,可以正常编译。
如果确实要在BarImpl中调用Foo的默认isEmpty实现,正确做法是在父类Bar中增加一个可访问的代理方法,因为在Bar的上下文里Foo是直接实现的接口,可以合法调用Foo.super.isEmpty():
public abstract class Bar<T> implements Foo<T> { ... protected boolean fooDefaultIsEmpty() { return Foo.super.isEmpty(); } }
之后在BarImpl的重写方法里直接调用fooDefaultIsEmpty()即可。
内容的提问来源于stack exchange,提问作者RedCrafter LP
相关产品推荐
相关产品推荐

