Java泛型名称冲突,具有相同的擦除

时间:2012-08-13 12:01:44

标签: java generics

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

public class Bar extends Foo

Foo中的功能:

protected void saveAll(Collection<?> many)

Bar中的功能:

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

获取错误:

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

我做错了什么?

6 个答案:

答案 0 :(得分:18)

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

public class Bar extends Foo<MyClass>

Foo<E>

中的功能
protected void saveAll(Collection<E> many)

和Bar中的功能:

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

答案 1 :(得分:8)

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

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

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

然后让Bar为您的特定类型实施Foo

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

答案 2 :(得分:4)

在运行时,参数类型将替换为Object。 因此saveAll(Collection<?>)saveAll(Collection<MyClass>)会转换为saveAll(Collection)。这是一个名字冲突。 查看here了解详情。

你可以这样做:

public class Foo<T> {
    protected void saveAll(Collection many) {
        // do stuff
    }
}

public class Bar extends Foo<MyClass> {
}

答案 3 :(得分:2)

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

尝试删除&lt; ..&gt;这可能会让它更清晰。当你把&lt; ...&gt;然后再考虑方法的名称。如果它们不同则应编译。

此外,我不认为这是一个休眠问题,所以应删除此标记。这是一个java泛型问题。

您可以在此处输入类

public class Bar extends Foo<MyClass>

然后将方法类型设为T

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

然后Foo的声明就像是

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

答案 4 :(得分:1)

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

最好使用Joshua Bloch撰写的Effective Java Second Edition中描述的PECS(Producer - Extends,Consumer - Super)规则。

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

在Foo课程中:

public class Foo<E>{

protected void saveAll(Collection<? super E> many){....}

protected void getAll(Collection<? extends E> many){....}

}

答案 5 :(得分:0)

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

<强>错误:

public class Bar<MyClass> extends Foo
{
    ...
}

<强>正确:

public class Bar extends Foo<MyClass>
{
    ...
}