Java 8默认方法继承

aig*_*guy 11 java interface multiple-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();
    }
}
Run Code Online (Sandbox Code Playgroud)

在这种情况下,如果main执行,则打印"hi from foo".为什么Foo执行优先?不Bar继承sayHi()从Base,因为如果MyClass是仅实现Bar,则Base执行将被称为?因此,代码仍然无法编译是有意义的.另外,既然Bar应该Base实现sayHi(),为什么我不能MyClass像下面那样覆盖它:

@Override
public void sayHi() {
    Bar.super.sayHi();
}
Run Code Online (Sandbox Code Playgroud)

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

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

bla*_*ide 13

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

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

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

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


Lou*_*man 12

在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 {}
Run Code Online (Sandbox Code Playgroud)

Right从Top继承name(),但Bottom从Left继承name(),而不是Right.这是因为Left中的name()会覆盖Top中name()的声明.

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

  • @aiguy那是......有点压倒一切.对于正常的类继承来说,_always_是正确的,overriding完全隐藏了超类型实现. (3认同)
  • @aiguy如果具体类依赖于原始实现,那么他们做错了. (3认同)