【问题标题】:Why does this overriding method declaration produce a compilation error? [duplicate]为什么这个覆盖方法声明会产生编译错误? [复制]
【发布时间】:2023-12-27 10:28:01
【问题描述】:

以下代码:

class Parent {
    public void method(List parameter){
    }
}

class Child extends Parent {

    public void method(List<String> parameter) {
    }
}

编译失败,出现以下错误:

Parent.java:12: error: name *: method(List<String>) in Child and method(List) in Parent have the same erasure, yet neither overrides the other
    public void method(List<String> parameter) {
                ^
1 error

但我正在检查第 8.4.8.1 节中的 JLS8 是否说:

在类 C 中声明或继承的实例方法 mC,覆盖 来自 C 类 A 中声明的另一个方法 mA,当且仅当满足以下所有条件时 是真的:

...

mC 的签名是 mA的签名。

...

在 §8.4.2 中它说:

如果满足以下任一条件,方法 m1 的签名是方法 m2 签名的子签名:

...

m1 的签名与 m2 签名的擦除(第 4.6 节)相同。

在这种情况下,原始方法声明和覆盖方法声明都具有相同的擦除,那么为什么编译会失败?

【问题讨论】:

  • List&lt;String&gt; 不是 List 的擦除,因此根据您引用的规范,它不是子签名。我想你把m1m2 搞混了。
  • 他们不是都被认为是类型擦除到List&lt;Object&gt;吗?。
  • 它们都被类型擦除为List,但你引用的规范不是关于它们是否有共同的擦除,而是关于子类的方法是否是超类方法的擦除。如果父类有List&lt;String&gt;,子类有List,那就没问题了。
  • @4castle,我明白了,我的问题弄错了,我该怎么办?编辑问题?还是因为问题本身的表述不正确而将其删除?

标签: java overriding jls


【解决方案1】:

因为,在类型擦除之后,只有List(如果你愿意,List&lt;Object&gt;)。我想你想要一个通用的Parent 喜欢

class Parent<T> {
    public void method(List<T> parameter){
    }
}

class Child extends Parent<String> {
    public void method(List<String> parameter) {
    }
}

【讨论】:

  • 我不确定你的第一句话是否回答了这个问题,因为 OP 提出了一个类似的案例,说明为什么它不应该是编译器错误。
  • 实际的父类属于遗留库,但无论如何我实际上并不是在寻找解决方案,而是编译器这样做的原因。
  • @JaimeHablutzel 因此,遗留代码(例如您在此处的代码)通过添加泛型类型(几乎完全是编译时类型检查系统)继续发挥作用。
【解决方案2】:

在这种情况下,原始方法声明和覆盖方法声明都具有相同的擦除,那么为什么编译会失败?

同样的擦除是不够的。再看看你引用的 JLS 部分:

方法 m1 的签名是 a 的签名的子签名 方法 m2,如果:

...

m1 的签名与签名的擦除(§4.6)相同 平方米。

这并不是说擦除必须相等。也就是说m1的签名必须是m2的签名的擦除。我们不会在这里删除 m1 的签名。

【讨论】:

  • 在这种情况下class Parent { void method(List&lt;String&gt; parameter){ } } class Child extends Parent { void method(List&lt;Object&gt; parameter) { } } 应该编译为 m1 的签名与擦除 m2 的签名相同,但事实并非如此。
  • @JaimeHablutzel:m1 和 m2 正好相反。
  • m1 和 m2 指的是正确的方法,我之前评论中示例的问题是List&lt;String&gt; 的类型擦除不是List&lt;Object&gt;,而只是List。以下示例阐明了 m1 is the same as the erasure of the signature of m2 何时正常工作 class Parent { void method(List&lt;String&gt; foo){ } } class Child extends Parent { void method(List bar) { } }
  • 您的回答实际上是在指出问题,因为@4castle 也发现了我的问题。我应该编辑问题,因为它的表述不正确,还是应该删除它,因为如果它只是询问 Why does this overriding method declaration produce a compilation error? 而没有引用 JLS(我没有正确解释),那么你的答案将不适用?