https://blog.csdn.net/s10461/article/details/53941091中泛型数组做一下补充总结。(这篇博客对于泛型总结得挺好)

在Java中是不能实例化参数化类型数组的,例如:

1
List<String>[] ls = new ArrayList<String>[10];

而使用通配符创建泛型数组是可以的,例如:

1
List<?>[] ls = new ArrayList<?>[10];

这样也是可以的:

1
List<String>[] ls = new ArrayList[10];

文中举了一个例子:

1
2
3
4
5
6
7
List<String>[] lsa = new List<String>[10]; // Not really allowed.    
Object o = lsa;
Object[] oa = (Object[]) o;
List<Integer> li = new ArrayList<Integer>();
li.add(new Integer(3));
oa[1] = li; // Unsound, but passes run time store check
String s = lsa[1].get(0); // Run-time error: ClassCastException.

对于oa[1] = li; 如果试图存储其他类型的元素,就会抛出一个ArrayStoreException异常,不过对于泛型类型,擦除会使这种机制无效。所以文中会说 Unsound, but passes run time store check(不健全,但通过运行时存储检查 )。

它的重点在下一句String s = lsa[1].get(0);抛出Run-time error: ClassCastException。在取出数据的时候却要做一次类型转换,所以就会出现ClassCastException,如果可以进行泛型数组的声明,上面说的这种情况在编译期将不会出现任何的警告和错误,只有在运行时才会出错。但通配符方式取出数据是会做显示的类型转换的,所以不会抛出这个运行时异常。这也就是为什么第一种情况不被允许而使用通配符创建泛型数组可以。

下面采用通配符的方式是被允许的:

1
2
3
4
5
6
7
List<?>[] lsa = new List<?>[10]; // OK, array of unbounded wildcard type.    
Object o = lsa;
Object[] oa = (Object[]) o;
List<Integer> li = new ArrayList<Integer>();
li.add(new Integer(3));
oa[1] = li; // Correct.
Integer i = (Integer) lsa[1].get(0); // OK