重写泛型类的方法时的名称冲突

时间:2014-12-01 14:47:19

标签: java generics method-overriding name-clash

我正在尝试通过以下代码了解名称冲突错误:

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的一些阅读,但在我看来,两种方法在使用或不使用泛型时都应该具有相同的擦除,因此在任何一种情况下都是有效的覆盖。 (请注意,我还没有在任何地方使用泛型参数,这就是为什么我很惊讶。)

我知道我之前已经向父类添加了泛型类型,但只收到有关子类的警告,而不是错误。任何人都可以解释这种情况吗?

1 个答案:

答案 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对应的通用声明中删除其类型。

(请注意,我们案例中的CBar。)

尝试覆盖方法时会发生同样的事情。尝试覆盖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) {
}

进一步阅读: