29

假设有两个接口Interface1Interface2where Interface2extends 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();
    }
}

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

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

4

1 回答 1

18

JLS 在15.12.3 中完全解决了这个问题。 “编译时第 3 步:选择的方法合适吗?” .

如果表单是TypeName 。极好的 。[TypeArguments] 标识符,然后:

  • […]
  • 如果TypeName表示一个接口,让T是立即包含方法调用的类型声明。如果存在与编译时声明不同的方法,该方法覆盖(第 9.4.1 节)来自直接超类或直接超接口的编译时声明,则会发生编译时错误T

JLS 继续解释为什么制定该规则:

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

所以它或多或少是专门用来阻止你做你想做的事情的。

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

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

于 2015-04-08T22:02:01.250 回答