【问题标题】:Java non-generic method hiding generic method with intersection typesJava非泛型方法隐藏具有交集类型的泛型方法
【发布时间】:2020-06-30 19:53:58
【问题描述】:

如果三个公共接口定义为:

public interface One{}
public interface Two{}
public interface Three{}

另外一个类 Super 被定义为:

public class Super {
    public static <E extends One & Two & Three> void hmm(E item) {}
}

为什么Super下面的子类会报编译错误?

public class Subber extends Super{
    public static void hmm(One item) {}
}

我希望上述方法可以简单地对 Super 隐藏该方法,但事实并非如此。

JLS (8.4.8.2) 说:

如果类 C 声明或继承静态方法 m,则称 m 隐藏任何方法 m',其中 m 的签名是 m' 签名的子签名(第 8.4.2 节),在超类中和 C 的超接口,否则这些超接口可以访问(第 6.6 节)以用 C 编写代码。

其中子签名在 8.4.2 中定义为:

如果两个方法或构造函数 M 和 N 具有相同的名称、相同的类型参数(如果有)(第 8.4.4 节),并且在将 N 的形式参数类型调整为M的类型参数,形式参数类型相同。

如果满足以下任一条件,方法 m1 的签名是方法 m2 签名的子签名: m2 与 m1 具有相同的签名,或者 m1 的签名与 m2 签名的擦除(第 4.6 节)相同.

根据 JLS 4.6,类型变量的擦除是其最左边界的擦除,因此: 据我了解,Subber 的 hmm 方法与 Super 的 hmm 方法的擦除相同,因此将是 Super 的 hmm 的子签名,因此意味着它会隐藏 Super 的 hmm。但是,我收到的错误消息(来自 eclipse),鉴于上述情况,这似乎没有意义:“Subber 类型的方法 hmm(One) 与 Super 类型的 hmm(E) 具有相同的擦除,但没有把它藏起来。”我错过了什么?

编辑:准确的错误消息,主要方法只包含Subber.hmm(null); 是:

Exception in thread "main" java.lang.Error: Unresolved compilation problem: 
    Name clash: The method hmm(One) of type Subber has the same erasure as hmm(E) of type Super but does not hide it

    at base/testpack4.Subber.hmm(Subber.java:4)
    at base/testpack4.Main.main(Main.java:5)

有人可以解释为什么 Subber 的方法无法编译,并引用可靠的来源(最好是 JLS)吗?

【问题讨论】:

  • 能否包含编译器错误信息?
  • 已添加,谢谢@matt b
  • 您的 Java 版本是多少?我无法在 Java 14 上重现它。
  • 可能是eclipse java编译器的bug
  • java.exe 和 javaw.exe 只是同一 JVM 的不同启动器(仅运行时)。不同的java编译器是javac.exe和ecj(java的eclipse编译器)

标签: java generics inheritance jls method-hiding


【解决方案1】:

...谁能解释一下为什么 Subber 的方法无法编译...

implemented the code you listed; 逐字逐句。我的 Main.main(String[]) 通过调用 Subber.hmm(null)Subber.hmm(One) 可以正常编译。

我唯一不同的是引入了一个新的Four接口,它满足&lt;E extends One &amp; Two &amp; Three&gt; void Super.hmm(E)的类型参数部分的要求。

然后我将 Four 的实例传递给 Subber.hmm(One) 以确认 Super.hmm(E) 没有被调用;证明它实际上是隐藏的。

...引用可靠来源(最好是 JLS)?...

That implementation 的行为与您引用的 JLS 规范完全一样。

【讨论】:

  • 是的,我猜它没有为我编译的原因是因为我使用的是eclipse编译器,在这方面它不完全符合JLS。我继续并将此答案标记为正确。
  • 酷!谢谢@SamHooper。当您遇到编译错误时,您在哪个版本的 Eclipse 和哪个 JDK 中运行?
  • 我使用的是 jdk 14.0.1,eclipse 版本为 2020-06 (4.16.0)。
【解决方案2】:

E 的类型还没有定义,你可以通过设置 Super 类的 E 泛型来参数化它,并在 Subber 类中定义它:

public class Super<E> {
    public static <E extends One & Two & Three> void hmm(E item) {}
}

public class Subber extends Super<One> {
    public static void hmm(One item) {}
}

【讨论】:

  • 不是Super&lt;E&gt;,只是Super。方法是参数化的,而不是类。
  • 是的,我明白,这就是问题所在。您可以在非泛型类中创建泛型方法,但该方法不会与泛型匹配以“覆盖”签名,它只会发生冲突,因为泛型处于方法级别而不是层次结构级别。
  • 如果您觉得自己知道问题所在,您应该引用正确的 JLS 位置,并在您的答案中更加详细。照原样,这个答案只是显示 不同 代码而不是问题中的代码。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-02-16
  • 1970-01-01
  • 2012-03-01
  • 2015-07-30
  • 1970-01-01
  • 1970-01-01
  • 2018-08-28
相关资源
最近更新 更多