Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/398.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 扩展其他接口的默认方法和接口_Java_Java 8_Default Method - Fatal编程技术网

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

Java 扩展其他接口的默认方法和接口,java,java-8,default-method,Java,Java 8,Default Method,假设有两个接口Interface1和Interface2,其中Interface2扩展了Interface1 interface Interface1 { default void method() { System.out.println("1"); } // Other methods } interface Interface2 extends Interface1 { @Override default void metho

假设有两个接口
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();
    }
}
然后:

这可以很好地编译,如果我实例化一个新的
MyClass
并调用
method()
,那么输出就是预期的
1


所以我的问题是,考虑到很容易绕过限制,您只能为链中最特定的接口编写
InterfaceName.super.method()
,那么限制的原因是什么?首先不允许您编写
Interface1.super.method()
,可以防止哪些问题?

JLS在“编译时步骤3:所选方法合适吗?”中准确地解决了这一问题

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

  • [……]
  • 如果TypeName表示接口,那么让
    T
    作为立即包含方法调用的类型声明如果存在不同于编译时声明的方法,该方法从
    T
    的直接超类或直接超接口重写()编译时声明,则会发生编译时错误
JLS接着解释了制定规则的原因:

如果超级接口覆盖了祖父母接口中声明的方法,则此规则通过将祖父母添加到其直接超级接口列表中,防止子接口“跳过”覆盖。访问祖父母功能的适当方式是通过直接超级接口,只有当该接口选择公开所需的行为时

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

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

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


如果
Interface2扩展了Interface1
,在哪种情况下您希望一个类同时实现它们?@marounnaroun您是对的,没有必要同时编写它们。只是在IntelliJ上,如果我只写了
Interface2
,我得到了一条不太有用的错误消息。在
interfaces
中的方法有一个主体,我想我必须修改我的基础知识。我以为他们应该是abstract@ShrikantHavale这是Java8的新特性。我几乎希望他们没有允许,因为它打开了一整罐蠕虫。@pbabcdefp如果你使用得当,就没有蠕虫罐(这个模糊的说法适用于许多其他概念)…这真的很有趣。它们对工作犬来说是好的(对我来说似乎是一个黑客),但是他们拒绝原来的唯一原因是他们不认为它是“合适的”。是的,我觉得奇怪。例如,如果javadoc自动检测子类选择使用哪个实现并生成适当的文档,我会理解。但我怀疑这是真的,因为,好吧,javadoc不关心方法的主体。我认为“他们同意”是对这个评论的误读(主要是听到你想听到的)。一般来说,这些规则是有充分理由的(这里甚至给出了理由);当编译器说“不要那样做”时,你的第一个想法不应该是“让我卸下刀锋护板,让保姆知道谁最聪明。”在这种情况下,不可能在所有情况下都阻止用户做愚蠢的事情,但仍然不推荐,这并不意味着我们应该放弃在可能的时候警告用户。@Radiodef公平评论。现实情况是:多重继承比单一继承更复杂,即使通过取缔状态的多重继承和选择巧妙的冲突解决规则,避免了90%的复杂性。用户有20年的“这就是继承/覆盖的含义”的经验,以单个继承为条件,当他们试图将其应用于多个继承时,他们的直觉往往会使他们失败。我们可以通过取缔真正有问题的部分来让它变得更容易,但是“更容易”和“更容易”是不一样的。@BrianGoetz,我明白了。因此,不管它有用与否,我们都有机会用我们熟悉的概念之外的功能(意大利面类型)来击打自己的脚,而且很难将这种可能性定为非法。(仔细考虑之后,似乎不允许使用覆盖规避技巧的冲突解决方案更为僵化,而不是有用。)再次感谢您的时间。
class MyClass implements Interface1, Interface2, Interface3 {

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