Java 8默认方法inheritance

假设有以下类型:

public interface Base { default void sayHi(){ System.out.println("hi from base"); } } public interface Foo extends Base { @Override default void sayHi(){ System.out.println("hi from foo"); } } public interface Bar extends Base { } public class MyClass implements Foo, Bar { public static void main(String[] args) { MyClass c = new MyClass(); c.sayHi(); } } 

在这种情况下,如果执行main ,则打印“hi from foo”。 为什么Foo的实现优先? Bar不inheritanceBase sayHi() ,因为如果MyClass只实现Bar ,那么Base实现会被调用吗? 因此,代码仍然无法编译是有意义的。 另外,由于Bar应该具有BasesayHi() ,为什么我不能在MyClass覆盖它,如:

 @Override public void sayHi() { Bar.super.sayHi(); } 

尝试这样做时会发生以下错误:

错误类型限定符Bar默认超级调用方法,sayHi()在Foo中被覆盖

在JLS 9.4.1中几乎使用您的确切示例来指定此行为,只是更改了一些名称:

 interface Top { default String name() { return "unnamed"; } } interface Left extends Top { default String name() { return getClass().getName(); } } interface Right extends Top {} interface Bottom extends Left, Right {} 

Right从Topinheritancename(),但Bottom从Leftinheritancename(),而不是Right。 这是因为Left中的name()会覆盖Top中name()的声明。

JLS似乎没有给出我能看到的任何特别具体的理由; 这就是Java设计者决定inheritance的方式。

这是设计的。 从JLS 15.12.3开始 :

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

  • 如果TypeName表示接口,则让T为紧邻方法调用的类型声明。 如果存在一个与编译时声明不同的方法,则会从直接超类或直接超级接口覆盖(第9.4.1节 )编译时声明,从而发生编译时错误。

在超级接口覆盖祖父表格接口中声明的方法的情况下,此规则通过简单地将祖父表添加到其直接超接口列表中来防止子接口“跳过”覆盖。 访问祖父母的function的适当方式是通过直接超级接口,并且仅当该接口选择暴露期望的行为时。 (或者,开发人员可以自由定义他自己的附加超接口,通过超级方法调用公开所需的行为。)