6

我试图理解使用以下代码得到的名称冲突错误:

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>)inBardoSomething(Number,Map<String,JComponent>)inFoo具有相同的擦除,但都不会覆盖另一个

我知道我可以通过从 中删除泛型类型Foo或将Bar声明更改为class Bar extends Foo<Integer>;来修复它。我想知道的是为什么在特定情况下会发生此错误,但是如果我comps从每个方法中删除参数就会消失。我已经阅读了有关类型擦除的一些内容,但在我看来,无论是否使用泛型,这两种方法都应该具有相同的擦除,因此在任何一种情况下都是有效的覆盖。(请注意,我什至还没有在任何地方使用过泛型参数,这就是我如此惊讶的原因。)

我知道我之前已经向父类添加了泛型类型,但只收到关于子类的警告,而不是错误。谁能解释这种情况?

4

1 回答 1

6

Luiggi 在评论中是正确的。这是原始类型的结果。

类的超类型可以是原始类型。类的成员访问被视为正常,超类型的成员访问被视为原始类型。在类的构造函数中,对 super 的调用被视为对原始类型的方法调用。

这适用于调用超类型方法时,也适用于重写方法时。

举个例子,下面

class Bar extends Foo {
    public Bar() {
        doSomething(1, new HashMap<Number, String>());
    }
}

您会注意到它可以编译,即使它HashMap<Number, String>不是可分配给Map<String, JComponent>.

C未从其超类或超接口继承的原始类型的构造函数(第 8.8 节)、实例方法(第 8.4 节、第 9.4 节)或非静态字段(第 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) {
}

进一步阅读:

于 2014-12-01T15:40:13.773 回答