假设有两个接口Interface1
和Interface2
Interface2
扩展Interface1
。
interface Interface1 {
default void method() {
System.out.println("1");
}
// Other methods
}
interface Interface2 extends Interface1 {
@Override
default void method() {
System.out.println("2");
}
// Other methods
}
假设我想创建一个实现Interface2
的类,但我希望method()
成为Interface1
中的版本。如果我写
class MyClass implements Interface1, Interface2 {
public void method() {
Interface1.super.method();
}
}
我收到编译错误:
默认超级调用中的错误类型限定符:冗余接口Interface1由Interface2
扩展
可以通过创建第三个界面来解决这个问题:
interface Interface3 extends Interface1 {
default void method() {
Interface1.super.method();
}
}
然后:
class MyClass implements Interface1, Interface2, Interface3 {
public void method() {
Interface3.super.method();
}
}
这编译得很好,如果我实例化一个新的MyClass
并调用method()
,则输出为1
。
所以我的问题是,鉴于它很容易绕过限制,你只能为链中最具体的接口写InterfaceName.super.method()
,限制的原因是什么?禁止您首先撰写Interface1.super.method()
会阻止哪些问题?
答案 0 :(得分:18)
JLS在15.12.3. “编译 - 时间步骤3:选择的方法是否合适?”确切解决了这个问题。
如果表单是 TypeName。 super。 [TypeArguments] Identifier ,然后:
- [...]
- 如果 TypeName 表示接口,则让
T
成为立即封闭方法调用的类型声明。 如果存在一个与编译时声明不同的方法,则会从直接超类或T
的直接超接口覆盖(§9.4.1)编译时声明,从而发生编译时错误强>
JLS继续解释为什么规则到位:
如果超级接口覆盖祖父表格接口中声明的方法,则此规则会阻止子接口通过简单地将祖父表添加到其直接超接口列表中来“跳过”覆盖。访问祖父母的功能的适当方式是通过直接超级接口,并且只有当该接口选择暴露所需的行为时才会这样。
因此,它或多或少存在专门阻止你做你想做的事情。
但JLS似乎也承认你的解决方法:
(或者,开发人员可以自由定义他自己的额外超接口,通过超级方法调用公开所需的行为。)