在重写generics类的方法时的名称冲突

我试图通过以下代码了解我得到的名称冲突错误:

import java.util.*; import javax.swing.*; class Foo { public void doSomething(Number n, Map comps) { } } class Bar extends Foo { public void doSomething(Number n, Map comps) { } } 

错误信息:

错误:名称冲突: Bar doSomething(Number,Map)Foo中的doSomething(Number,Map)具有相同的擦除,但都没有覆盖其他

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

我知道我之前已经向父类添加了generics类型,但只获得了有关子类的警告,而不是错误。 有谁能解释这个场景?

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

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

这适用于调用超类型方法,但也适用于覆盖超类型方法。

举例来说,以下内容

 class Bar extends Foo { public Bar() { doSomething(1, new HashMap()); } } 

您会注意到它编译,即使HashMap不是可分配给Map

未从其超类或超接口inheritance的原始类型C的构造函数(第8.8节),实例方法(第8.4节,第9.4节)或非静态字段(第8.3节)的类型是对应于的原始类型在与C对应的generics声明中擦除其类型。

(注意,在我们的例子中CBar 。)

尝试覆盖方法时会发生同样的事情。 当试图覆盖Foo#doSomething(..)方法时, Bar类实际上看到它被声明为

 public void doSomething(Number n, Map comps) { } 

换句话说,类型参数的每次使用都被擦除。 所以试图声明方法

 public void doSomething(Number n, Map comps) { } 

在子类型Bar中实际上是尝试重载,而不是覆盖。 由于类型擦除,这会失败。 您可以使用@Overridevalidation的正确覆盖是

 public void doSomething(Number n, Map comps) { } 

进一步阅读:

  • 什么是原始类型,为什么我们不应该使用它?