一些Java泛型问题

时间:2017-12-24 10:23:47

标签: java generics

我目前正在从一本书中学习Java Generics,有一些我不太了解的事情。

假设我有一个参数化类:

class MyClass<T> { 

    T item;

    public T getItem() { return item; }

    // ...
}

据我所知,由于类型擦除,禁止创建参数化类型的数组。现在这本书说我可以像这样使用演员表:

MyClass<String>[] foo = (MyClass<String>[]) new MyClass<?>[10];

但是以下声明有什么区别?

MyClass<String>[] foo = new MyClass[10];

在运行时的两种情况下,JVM只知道foo是原始类型MyClass[]吗?

现在这本书继续说:

&#34;结果不安全。如果您在MyClass<OtherType>中存储foo[0],然后在String上调用foo[0].getItem()方法,则会获得ClassCastException。 提示:如果您需要收集参数化类型对象,只需使用ArrayListArrayList<MyClass<String>>是安全有效的。&#34;

在这种情况下,ArrayList的使用方式更安全吗?我可以通过在列表中存储ClassCastException来轻松生成MyClass<OtherType>

编辑:我对任何答案都不满意。问题仍然存在:ArrayList在哪种方式更安全?任何人都可以给我一些证明安全性提高的具体例子吗?

对我最初的未经编辑的帖子进行以下评论:

&#34;我认为这本书不能很好地解释这一点,或者你已经脱离了背景。问题是当您尝试创建泛型参数类型的数组时,例如在MyClass中你做T[] items = (T[]) new Object[10];&#34;

问题是什么?

// Please don't comment about any problems related to bounds etc. This class should serve purely 
// for demonstration of the core issue I'm trying to understand
public class MyClass<T> {

    private T[] items = (T[]) new Object[10];

    private int size = 0;

    public void addItem(T item) {
        items[size++] = item;
    }

    public T getItem(int index) {
        return items[index];
    }
}

具体来说,我失去了ArrayList可以提供的任何类型安全吗? 请注意,我并未尝试使用带参数化类型的数组,我确信集合实际上表现更好,我只是想了解为什么他们这样做以及使用数组会产生什么问题。

1 个答案:

答案 0 :(得分:1)

使用泛型集合与裸数组“更安全”的原因是因为编译器增加了额外的保证,即您的代码将执行预期的操作,因为它不太可能混合使用不同类型参数创建的对象的引用由于你的部分编码错误。

例如,将MyClasses的混合添加到MyClass数组中是完全合法的:

MyClass<Integer> mcInt = new MyClass<Integer>();
MyClass<String> mcString = new MyClass<String>();
MyClass[] array = new MyClass[] { mcInt , mcString }; 
...
MyClass<String>[] typedArray = (MyClass<String>[]) array;

以上可能编译好(取决于你如何处理不安全的警告),但是,typedArray将包含对MyClass<Integer>类型元素的无效引用。

使用泛型集合时,等效代码将无法编译,因为编译器由于使用泛型提供的类型安全性增加,因此意识到您正在添加该无效引用。

MyClass<Integer> mcInt = new MyClass<Integer>();
MyClass<String> mcString = new MyClass<String>();
List<MyClass<String>> list = new ArrayList<MyClass<String>>(); 
list.add(mcString); // is ok.
list.add(mcInt); // won't compile.

欢迎使用裸阵列,但这样做会导致编译器失去额外的检查。实际上可以使用不安全的数组,如果它们是私有字段或局部变量,当你确定你的代码实际上是安全的时,你会特别小心并使用@SuppressWarnings(“unchecked”)静音警告。如果你使用泛型,那就确定了。

根据我的经验,大多数时候最好只是随时使用通用集合,但有时候你可能会遇到不安全的替代方案由于性能而更加方便的情况,或者仅仅因为安全的替代方案会导致更加麻烦代码。