类型擦除和继承:当从子类访问时,List <number>的对象被视为原始列表?</number>

时间:2012-06-21 07:10:47

标签: java generics type-erasure

问题:

当从子类访问时,参数化类的对象被视为非泛型。我该如何克服这个问题?

详细说明:

考虑一个基类:

public class MyBaseClass {
    protected List<Number> numbers = new ArrayList<Number>();

    public MyBaseClass(){
        //...
    }
}

现在,让我们扩展这个类:

public class MyDerivedClass extends MyBaseClass {

    public void addSomething() {
        numbers.add(25.0f); //Warning about type-safety here
    }
}

在派生类中,数字对象被视为原始类型。警告是:

  

类型安全:方法add(Object)属于原始类型List。应该参数化对泛型类型List的引用。

如果我尝试自己添加type参数,则会出现编译错误:

        numbers.<Number>add(25.0f); //Error here

我看到的错误是:

  

List类型的方法add(Number)不是通用的;它不能用参数

参数化

但是,如果我将这两个类放在同一个Java源文件中,那么这个问题就会消失。首先没有警告。这是一个说明问题的样本。

在我的实际应用程序中,我希望能够从派生类中的List获取元素,并对它们执行特定于类的操作,而不必先将检索到的对象强制转换为适当的类型。 / p>

我怀疑问题是因为类型擦除,但我无法弄清楚如何解决它。


编辑:

我在Fedora Core 16上使用Eclipse 3.7.2和Oracle JDK 1.6.0_30。使用默认合规性设置将编译器合规性设置为1.6。正如我所提到的,如果我将两个类放在同一个.java文件中,那么我就看不到警告了。只有将它们放在不同的文件中才能看到它。

我可以通过定义直接操作父类中的列表对象的所有方法来解决这个问题。并从派生类中使用它。

但我仍然很好奇为什么我会看到这个警告。这是解决方法:

在MyBaseClass中:

    protected void addNumberToList(Number num){
        numbers.add(num);
    }

然后在派生类中:

    public void addSomething() {
        addNumberToList(25.0f);
    }

同样,所有直接操作List对象的操作都可以在基类中。

2 个答案:

答案 0 :(得分:3)

您的真正的基类是通用的,但您的子类继承自其原始类型:

public class MyBaseClass<X> {
    protected List<Number> numbers = new ArrayList<Number>();

    public List<Number> getNumbers() {
        return numbers;
    }
}

public class MyDerivedClass extends MyBaseClass {
    public void addSomething() {
        numbers.add(25.0f);
    }
}

JLS §4.8表示会员访问权限将被视为原始类型。这意味着numbers被视为原始,因此警告。解决方案是参数化超类型:

public class MyDerivedClass extends MyBaseClass<TypeArgumentsHere>

答案 1 :(得分:0)

我使用Eclipse并且您的代码完全符合,没有任何警告或错误。但我认为你应该提供protected/public方法,而不是暴露实例变量。

public class MyBaseClass {
    protected List<Number> numbers = new ArrayList<Number>();

    public List<Number> getNumbers() {
        return numbers;
    }
}

public class MyDerivedClass extends MyBaseClass {

    public void addSomething() {
        getNumbers().add(25.0f);
    }
}