我正在尝试通过以下代码了解名称冲突错误:
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
和doSomething(Number,Map<String,JComponent>)
中的Foo
具有相同的内容 擦除,但都没有覆盖其他
我知道我可以通过从Foo
删除通用类型或将Bar
声明更改为class Bar extends Foo<Integer>
来解决此问题。我想知道的是为什么在特定情况下会发生此错误,但如果我从每个方法中删除comps
参数,则会消失。我已经完成了关于type erasure的一些阅读,但在我看来,两种方法在使用或不使用泛型时都应该具有相同的擦除,因此在任何一种情况下都是有效的覆盖。 (请注意,我还没有在任何地方使用泛型参数,这就是为什么我很惊讶。)
我知道我之前已经向父类添加了泛型类型,但只收到有关子类的警告,而不是错误。任何人都可以解释这种情况吗?
答案 0 :(得分:6)
Luiggi is right in the comments.这是raw types的结果。
类的超类型可以是原始类型。会员访问 class被视为正常,超类型的成员访问是 处理原始类型。在类的构造函数中,调用 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节),或者 原始类型
C
的非静态字段(第8.3节),它不是从其继承的 超类或超接口是对应的原始类型 在与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) {
}
进一步阅读: