我试图理解使用以下代码得到的名称冲突错误:
import java.util.*;
import javax.swing.*;
class Foo<R extends Number> {
public void doSomething(Number n, Map<String, JComponent> comps) {
}
}
class Bar extends Foo {
public void doSomething(Number n, Map<String, JComponent> comps) {
}
}
错误信息:
错误:名称冲突:
doSomething(Number,Map<String,JComponent>)
Bar
和Foo
doSomething(Number,Map<String,JComponent>)
有相同的 擦除,但两者都不会覆盖另一个
我知道我可以通过从Foo
中删除泛型类型或将Bar
声明更改为class Bar extends Foo<Integer>
来修复它;我想知道的是为什么在特定情况下会发生此错误,但如果我从每个方法中删除comps
参数,则会消失。我已经阅读了一些关于类型擦除的内容,但在我看来,这两种方法都应该具有相同的擦除,无论是否具有泛型,因此在任何一种情况下都是有效的覆盖。(请注意,我什至还没有在任何地方使用通用参数,这就是我如此惊讶的原因。
我知道我之前已经向父类添加了泛型类型,但只收到有关子类的警告,而不是错误。谁能解释这种情况?
Luiggi在评论中是正确的。这是原始类型的结果。
类的超类型可以是原始类型。会员访问 类被视为正常类,超类型的成员访问为 与原始类型一样处理。在类的构造函数中,调用 super 被视为对原始类型的方法调用。
这适用于调用超类型方法,也适用于重写超类型方法。
举个例子,下面
class Bar extends Foo {
public Bar() {
doSomething(1, new HashMap<Number, String>());
}
}
您会注意到它会编译,即使HashMap<Number, String>
不是可分配给 Map<String, JComponent>
的类型。
构造函数的类型 (§8.8(、实例方法的类型 (§8.4, §9.4( 或 原始类型的非静态字段 (§8.3(
C
,不是从其继承的 超类或超接口是对应于 在对应于C
的通用声明中擦除其类型。
(请注意,在我们的例子中C
是Bar
。
尝试重写方法时也会发生同样的事情。尝试重写 Foo#doSomething(..)
方法时,Bar
类实际上看到它被声明为
public void doSomething(Number n, Map comps) {
}
换句话说,类型参数的每个用法都会被擦除。所以尝试声明方法
public void doSomething(Number n, Map<String, JComponent> comps) {
}
在子类型中,Bar
实际上是尝试重载,而不是覆盖。由于类型擦除,这失败了。您可以使用@Override
验证的正确覆盖是
public void doSomething(Number n, Map comps) {
}
延伸阅读:
- 什么是原始类型,为什么我们不应该使用它?