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 super E> many){....} protected void getAll(Collection extends E> many){....} }
虽然现有答案是正确的,但是当您声明实际类型不在“ extends
…”子句中但在实际类名中时,很容易发生此错误:
错误:
public class Bar extends Foo { ... }
正确:
public class Bar extends Foo { ... }