Java 实现两个接口并解决默认方法冲突:为什么要使用 super 关键字?

Java implementing two interfaces and resolving default method conflicts: why using super keyword?

Java 解决默认方法冲突:为什么使用 super 关键字?

我正在看书 "Core Java SE 9 for the impatient"。在部分 "Resolving Default Method Conflicts",我发现解析的时候 默认方法冲突,使用 super 关键字。但我不 理解为什么使用 super 关键字。

来自这个link:https://docs.oracle.com/javase/tutorial/java/IandI/override.html 我知道 super 关键字是必需的(否则程序将无法编译)。

但这似乎违反直觉。据我了解,界面 “Identified”没有超 class。为什么不直接使用“return Identified.getId();”?

public interface Person {
    default int getId() {
        return 0;
    }
}

public interface Identified {
    default int getId() {
        return Math.abs(hashCode());
    }
}

public class Employee implements Person, Identified {
    public int getId() {
        return Identified.super.getId();
    }
}

question and this question 中有一些解释,但其中 none 解释了为什么使用关键字 super

因为 Identified.getId() 意味着 getId 是一个 static 方法。在Java8之前,这个super关键字只是用来引用一个超级class,形式是super.getId().

在你的情况下,Identified.super.getId() 并不意味着 "The getId() of the super of Identified",而是 "The getId() of the super that is from Identified"。

因为 Indentified.getId() 语法已经用于静态方法调用。 C++ 语法 Identifier::getId() 本来可以很好,但是 Java 将它用于方法引用,因此 no-go 也是如此。 Identified.this.getId() 语法也不能使用,因为当您嵌套了 classes.

时,它已经用于从外部 class 调用方法

我想在某些时候他们只是 运行 没有选择。但我同意语法可能有点误导,但由于在 Java 中你不能调用 "grandparent" 方法,因此使用 "super" 可能被视为较小的邪恶。

很明显Employee有冲突; PersonIdentified 的方法签名 default int getId() 相同.

JLS 9.4.1.3 将此描述为导致错误的行为冲突。当然,您必须决定应该调用哪个 getId() 方法(覆盖它,或者从 PersonIdentified 中选择默认实现。

JLS 9.4.1.1 (Overriding by Instance Methods) 提供了一个线索:

An overridden default method can be accessed by using a method invocation expression (§15.12) that contains the keyword super qualified by a superinterface name.

但是使用 super 这个词的最正式的原因来自 JLS 15.12,特别是 15.12.1:Compile-Time 第 1 步:确定 Class 或接口搜索

该部分描述了方法调用可以采用的 6 形式

一种形式是 Identified.getId() 保留用于静态引用,并在另一个答案中讨论。

另一种形式是super.getId()。这是super这个词更常见的用法;它指的是 class.

的 superclass

这导致15.12.1中提到的最终形式:TypeName.super.getId()

超级这个词在这里只有一个目的。如果单词 super 出现在方法 getId() 的左侧,并且如果 TypeName 出现在 super 的左侧,则 (i) TypeName 必须是 class 或接口,(ii) 如果 TypeName 是 class 它优先于接口,(iii) 如果 TypeName 不是 class 它必须是一个接口。

所以这最终导致了在这种情况下对super的解释:

Super 在这种情况下用于 匹配形式 TypeName.super.identifier 这是定义的方式(由 JLS 15.12. 1) 从接口 TypeName.

调用方法标识符