默认方法和扩展其他接口的接口

2022-09-01 12:17:24

假设有两个接口和扩展 。Interface1Interface2Interface2Interface1

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
}

假设我想创建一个实现的类,但我想成为 中的版本。如果我写Interface2method()Interface1

class MyClass implements Interface1, Interface2 {

    public void method() {
        Interface1.super.method();
    }
}

我收到编译错误:

默认超级调用中的错误类型限定符:冗余接口接口接口 1 由接口 2 扩展

可以通过创建第三个接口来解决此问题:

interface Interface3 extends Interface1 {

    default void method() {
        Interface1.super.method();
    }
}

然后:

class MyClass implements Interface1, Interface2, Interface3 {

    public void method() {
        Interface3.super.method();
    }
}

这编译得很好,如果我实例化一个新的并调用,输出是预期的。MyClassmethod()1

所以我的问题是,鉴于绕过限制非常容易,以至于你只能为链中最具体的接口编写,那么限制的原因是什么?首先禁止你写作可以防止哪些问题?InterfaceName.super.method()Interface1.super.method()


答案 1

JLS 在 15.12.3 中完全解决了这个问题。“编译时步骤 3:所选方法是否合适?

如果表单是 TypeName .super 。[类型参数] 标识符,然后:

  • [...]
  • 如果 TypeName 表示接口,则让它成为立即包含方法调用的类型声明。如果存在一个与编译时声明不同的方法,该方法从 T 的直接超类或直接超接口重写 (§9.4.1) 编译时声明,则会发生编译时错误。T

JLS继续解释了为什么该规则已经到位:

如果超接口重写在祖父接口中声明的方法,则此规则可防止子接口通过简单地将父接口添加到其直接超接口列表中来“跳过”重写。访问祖父母功能的适当方法是通过直接超接口,并且仅当该接口选择公开所需的行为时。

因此,它或多或少地存在,专门用于阻止你做你想做的事情。

但JLS似乎也承认您的解决方法:

(或者,开发人员可以自由地定义自己的附加超接口,该超接口通过超级方法调用公开所需的行为。


答案 2

推荐