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

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java实现两个接口并解决默认方法冲突:为什么使用super关键字?相关的知识,希望对你有一定的参考价值。

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

我正在阅读“不耐烦的核心Java SE 9”这本书。在“解决默认方法冲突”一节中,我发现在解决默认方法冲突时,会使用super关键字。但我不明白为什么要使用super关键字。

从这个链接:https://docs.oracle.com/javase/tutorial/java/IandI/override.html我知道需要super关键字(否则程序将无法编译)。

但这似乎违反直觉。根据我的理解,界面“Identified”没有超级类。为什么不使用“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和这个question有一些解释,但没有一个解释为什么使用关键字super

答案

因为Identified.getId()意味着getIdstatic方法。在Java 8之前,这个super关键字仅用于引用super.getId()形式的超类。

在你的情况下,Identified.super.getId()并不意味着“已鉴定的超级的getId()”,而是“来自已识别的超级的getId()”。

另一答案

很显然,Employee有冲突; default int getId()Person的方法签名Identified是相同的。

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

JLS 9.4.1.1(按实例方法覆盖)提供了一个线索:

可以使用方法调用表达式(第15.12节)访问重写的默认方法,该表达式包含由超级接口名称限定的关键字。

但使用super这个词最正式的原因来自JLS 15.12,特别是15.12.1:编译时间步骤1:确定要搜索的类或接口

本节描述了方法调用可以采用的6种形式。

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

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

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

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

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

在这种情况下,超级用于匹配形式TypeName.super.identifier,它是定义的方式(通过JLS 15.12.1)从接口TypeName调用方法标识符。

另一答案

因为Indentified.getId()语法已经用于静态方法调用。 C ++语法Identifier::getId()本来可以很好,但Java正在使用它进行方法参考,所以不用了。无法使用Identified.this.getId()语法,因为当您有嵌套类时,它已经用于外部类的avecà方法。

我想在某些时候他们只是没有选择。但我同意语法可能有点误导,但是因为在Java中你不能称之为“祖父母”方法,使用“超级”可能被视为较小的邪恶。

以上是关于Java实现两个接口并解决默认方法冲突:为什么使用super关键字?的主要内容,如果未能解决你的问题,请参考以下文章

《Java8实战》读书笔记08:接口的默认方法

《Java8实战》读书笔记08:接口的默认方法

Java中解决继承和接口默认方法冲突

java遗珠之接口方法

JAVA多继承例子

JAVA多继承例子