无法编译实现没有类型参数的接口的类

时间:2010-10-01 10:58:29

标签: java generics override type-erasure type-parameter

我有以下测试代码:

public interface Container<I> {
    public void addClass(Class<?> clazz);
}

public class MyContainer implements Container {
    public void addClass(Class<?> clazz) {}
}

我在尝试编译这两个类时遇到以下错误:

  

MyContainer.java:1:MyContainer不是抽象的,不会覆盖Container中的抽象方法addClass(java.lang.Class)

如果我在MyContainer中向Container界面添加一个类型(例如<Object>),我就不会收到错误。

问题是我将类型参数引入到Container,它是公共API的一部分,因此为了兼容性,我不能让所有实现类都无法编译。

有人有什么想法吗?这是类型擦除问题吗?有解决方法吗?

4 个答案:

答案 0 :(得分:7)

我认为问题在于,如果你在类声明中的任何地方使用原始类型,那么你就会选择退出泛型。所以这将有效 - 请注意参数更改。

public class MyContainer implements Container {
    public void addClass(Class clazz) {}
}

来自section 4.8 of the JLS

  

超类(分别为   原始类型的超级接口)   超类的擦除   (超级接口)的任何一个   参数化调用。

相信这是相关位...... Container<T>.addClass(Class<?> clazz)的删除是addClass(Class clazz)

但是,基本上除非这是真正的遗留代码,否则你应该考虑将一个类型参数作为一个重大变化引入接口。

答案 1 :(得分:3)

如果<?>修复了它,那就摆脱它:

public void addClass(Class clazz) {}

错误消息不是很具描述性:

  

名称冲突:MyContainer类型的方法addClass(Class)与Container类型的addClass(Class)具有相同的擦除,但不会覆盖它

这意味着当它们的类型被擦除时,两个方法都是相同的,但是子类方法实际上并没有实现/覆盖超类/接口中的方法。这没有多大意义,我认为这是因为你选择不在你的子类中使用泛型,你必须坚持(而不是perameterize Class

答案 2 :(得分:3)

如果你的班级使用泛型,那么一个简单的解决方案就是:

interface Container<I> {
    public void addClass(Class<?> clazz);
}

class MyContainer<I> implements Container<I> {
    public void addClass(Class<?> clazz) {}
}

或者,如果您已经知道您拥有的Container类型,

class MyContainer implements Container<ContainerType> {
    public void addClass(Class<?> clazz) {}
}

如果您的班级不使用Generics(1.5之前版本),则您不能拥有<?>部分。所以这里不会有任何实际问题。

class MyContainer implements Container {
    public void addClass(Class clazz) {}
}

答案 3 :(得分:0)

按如下方式实现您的界面应该有效(根据类型擦除):

public class MyContainer implements Container {
    public void addClass(Class clazz) {}
}