Javagenerics名称冲突,具有相同的擦除

我有超级Foo。 还有一个扩展它的类吧。

public class Bar extends Foo 

Foo中的function:

 protected void saveAll(Collection many) 

栏中的function:

 public void saveAll(Collection stuff) { super.saveAll(stuff); } 

得到错误:

  Name clash: The method saveAll(Collection) of type Bar has the same erasure as saveAll(Collection) of type Foo but does not override it. 

我究竟做错了什么?

您使用不兼容的类型覆盖saveAll方法。 也许你想做的事情如下:

 public class Bar extends Foo 

函数在Foo

 protected void saveAll(Collection many) 

和Bar中的function:

 public void saveAll(Collection stuff) { super.saveAll(stuff); } 

由于Java的类型擦除function,JVM将无法知道它是具有参数化类型MyClass还是应该调用的第一个类型的方法。

如果可能或适用,我见过避免这种情况的最常用模式是将类Foo更改为具有参数化类型:

 public class Foo { protected void saveAll(Collection many) {} } 

然后让Bar简单地为您的特定类型实现Foo

 public class Bar extends Foo { public void saveAll(Collection many) { super.saveAll(many); } } 

在运行时,参数类型将替换为Object 。 因此saveAll(Collection)saveAll(Collection)被转换为saveAll(Collection) 。 这是一个名字冲突。 在这里查看详情。

你可以这样做:

 public class Foo { protected void saveAll(Collection many) { // do stuff } } public class Bar extends Foo { } 

当编译器编译为字节代码时,会发生一个名为Erasure的进程。 这将从集合中删除类型信息。 我相信它将手动执行转换等作为生成字节代码的过程的一部分。 如果删除类的通用部分(即<..>),则会看到有两个saveAll方法。 错误是你有两个保存所有方法将相同的签名。 集合在字节代码中具有类型对象。

尝试删除<..>,这可能会更清楚。 当你把<...>放回去时,请考虑方法的名称。 如果它们不同则应编译。

此外,我不认为这是一个hibernate问题,所以应删除此标记。 这是一个javagenerics问题。

你在这里可以做的是键入类

 public class Bar extends Foo 

然后将方法类型设置为T.

 public void saveAll(Collection stuff) { super.saveAll(stuff); } 

然后Foo的声明会是这样的

 public abstract class Bar extends Foo { public void saveAll(Collection stuff) { } 

您只需使用不同的签名覆盖方法。

什么是好主意是使用Joshua Bloch在Effective Java Second Edition中描述的PECS(生产者 – 扩展,消费者 – 超级)规则。

根据这条规则它应该是这样的。

在Foo类中:

 public class Foo{ protected void saveAll(Collection many){....} protected void getAll(Collection many){....} } 

虽然现有答案是正确的,但是当您声明实际类型不在“ extends …”子句中但在实际类名中时,很容易发生此错误:

错误:

 public class Bar extends Foo { ... } 

正确:

 public class Bar extends Foo { ... }