隐藏接口的默认方法

Shadowing default method of an interface

考虑以下情况,

interface IFace1 {
    default void printHello() {
        System.out.println("IFace1");
    }
}

interface IFace2 {
    void printHello();
} 

public class Test implements IFace1, IFace2 {

    public static void main(String[] args) {
        Test test = new Test();
        test.printHello();

        IFace1 iface1 = new Test();
        iface1.printHello();

        IFace2 iface2 = new Test();
        iface2.printHello();
    }

    @Override
    public void printHello() {
        System.out.println("Test");
    }
}

在上面的示例中,我得到以下输出,这是 相当 预期的。

Test
Test
Test

我一直在阅读 Java-8 默认方法,特别是 Extending Interfaces That Contain Default Methods

2nd bullet : Redeclare the default method, which makes it abstract.

在上面的示例中,我有两个具有相同名称的默认方法的接口,当我实现这两个接口时,我只能实现 TestprintHello 的实现,它指的是 IFace2.

我对此没什么疑问,

  1. 我如何才能达到IFace1printHello方法,如果我不能为什么 ?
  2. 这种行为不会让我远离 IFace1 的预期性质吗? 可能 现在被其他方法掩盖了?

Quote 说,您可以在其子界面中创建 default 方法 abstract例如,

interface IFace2 extends IFace1 {
    void printHello();
}

在这里,当我实现 IFace2 时,我实际上无法达到 IFace1default 方法,这正是我的情况。

How can I reach to the printHello method of IFace1 and if I can't than why ?

您只能在实现 IFace1

的类型的实例方法中执行此操作
IFace1.super.printHello(); // only if IFace1 declares a default implementation of the method

换句话说,您不能通过 IFace1Test (或其他)类型的简单引用来实现。那会破坏封装。

Doesn't this behavior keep me away from the intended nature of IFace1 which is may be now shadowed by other method ?

这里没有阴影。您已覆盖该方法,因此将调用覆盖的方法。

关于你的第三个问题,你没有扩展任何接口,所以我看不出相关性。

如果你真的有

interface IFace2 extends IFace1 {
    void printHello();
}

public class Test implements IFace2 {

那么您将无法访问 IFace1default 方法实现。您永远不能跳过超类型来访问继承层次结构中更高层的实现。

看来您对 default 方法的存在有点困惑。所以让我们暂时忘记 IFace1.printHello() 是一个 default 方法。那么,就有一个明确的情况:Test实现了IFace1IFace2两个接口,恰好有同名同签名的方法

Test 实现了该方法,因此为两个接口都实现了该方法。 default 方法的新功能不会改变此逻辑的任何内容。此外,语言设计者注意添加 default 方法不会影响现有代码的行为,因此如果您的 class 实现了该方法,default 方法的存在就变得无关紧要了。

但是,如果您编写的代码知道 default 方法的存在,您可以调用它,如果它是由直接超级接口声明或继承的,即在您的代码中您可以使用 IFace1.super.printHello() 调用 IFace1.

default 方法

规则与超级classes的规则没有太大区别。如果您更改接口,使接口 IFace2 扩展 IFace1 并且仍将 printHello() 声明为 abstract 方法,那么此 abstract 方法会覆盖 default 方法,您不能再从 Test 中调用 IFace1.super.printHello()

如前所述,这些规则与普通实例方法没有太大区别。如果 Test 声明了一个方法 printHello(),那就是 只有 方法,您可以通过对 Test 实例的引用来调用该方法,而不管其声明的类型是否是 TestIFace1IFace2。只有 Test 本身的实现方法可以进行 super 次调用。


当涉及可能的接口多重继承时,主要区别就开始发挥作用。如果你的classTest确实没有实现方法printHello(),就看两个接口的继承关系了,会怎么样

  • 如果 IFace2 扩展了 IFace1,它的抽象方法重新声明了 default 方法,因此会出现编译器错误,因为 Test 必须实现 abstract方法
  • 如果IFace2不继承IFace1,则有两个同名同签名的可继承方法不明确,因此Test不会继承default方法,并且发生编译器错误,因为 Test 必须实现 abstract 方法
  • 如果IFace1扩展IFace2Test将继承default方法。如果 Test 没有实现 IFace2,它也会继承它,但这应该令人惊讶……