【问题标题】:Java implementing two interfaces and resolving default method conflicts: why using super keyword?Java 实现两个接口并解决默认方法冲突:为什么使用 super 关键字?
【发布时间】:2018-03-03 04:17:22
【问题描述】:

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

我正在阅读《Core Java SE 9 for the impatient》一书。在部分 “解决默认方法冲突”,我发现解决时 默认方法冲突,使用 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() 是静态的。您想返回super.getId() 并使用Identified 告诉编译器使用哪个冲突方法。把它想象成(Identified.super).getId()
  • 这实际上很令人困惑,想想看。这与 T.super.x 的其他用法不一致,即将引用的对象视为 T 的超类的实例(参见 §15.11.2)。我认为直观地使用合格的this (如Identified.this.getId())可能更有意义,但这可能会给设计师带来更多的歧义。
  • @Radiodef 或 IMO 可以说像 super.Identified.getId() 这样的话会更简洁,因为我不知道 which super。但无论哪种方式,这都是一个非常令人困惑的语法

标签: java interface multiple-inheritance


【解决方案1】:

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

在您的情况下,Identified.super.getId() 不是指“已识别的超级的 getId()”,而是“来自已识别的超级的 getId()”。 p>

【讨论】:

    【解决方案2】:

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

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

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

    可以通过使用方法来访问被覆盖的默认方法 包含关键字 super 的调用表达式(第 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 不是一个类,它必须是一个接口。

    所以这最终导致了super在这个上下文中的解释:

    在这种情况下,Super 用于匹配表单 TypeName.super.identifier 这是定义的方式(由 JLS 15.12.1)从接口 TypeName 调用方法标识符.

    【讨论】:

      【解决方案3】:

      因为Indentified.getId() 语法已经用于静态方法调用。 C++ 语法 Identifier::getId() 本来可以很好,但 Java 将它用于方法引用,所以也不行。 Identified.this.getId() 语法也不能使用,因为当您有嵌套类时,它已经用于从外部类中获取方法。

      我猜在某些时候他们只是没有选择。但我同意这种语法可能会产生误导,但由于在 Java 中不能调用“祖父”方法,因此使用“super”可能被视为一种较小的邪恶。

      【讨论】:

        猜你喜欢
        • 2015-12-04
        • 1970-01-01
        • 2014-05-20
        • 1970-01-01
        • 2016-02-26
        • 1970-01-01
        • 2015-12-16
        • 1970-01-01
        相关资源
        最近更新 更多