Java不能创建泛型数组的解决方案

Java不能创建泛型数组的解决方案

问题提出:

在java中是”不能创建一个确切的泛型类型的数组”的。

也就是说下面的这个例子是不可以的:

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

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

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

这样也是可以的:

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

下面使用Sun的一篇文档的一个例子来说明这个问题:

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.

这种情况下,由于JVM泛型的擦除机制,在运行时JVM是不知道泛型信息的,所以可以给oa[1]赋上一个ArrayList而不会出现异常,但是在取出数据的时候却要做一次类型转换,所以就会出现ClassCastException,如果可以进行泛型数组的声明,上面说的这种情况在编译期将不会出现任何的警告和错误,只有在运行时才会出错。

而对泛型数组的声明进行限制,对于这样的情况,可以在编译期提示代码有类型安全问题,比没有任何提示要强很多。

解决方案

1. 通配符

The Java™ Tutorials: Generics给出的解决方案如下:

List<?>[] lsa = new List<?>[10];                //1
List<Integer> li = new ArrayList<Integer>();
li.add(new Integer(3));
// Correct.
lsa[1] = li;
// Run time error, but cast is explicit.
Integer s = (Integer) lsa[1].get(0);              //2

借助于无限定通配符却可以,? 代表未知类型,所以它涉及的操作都基本上与类型无关,因此 jvm 不需要针对它对类型作判断,因此它能编译通过,但是,只提供了数组中的元素因为通配符原因,它只能读,不能写。比如,上面的 lsa 这个局部变量,它只能进行 get() 操作,不能进行 add() 操作。当操作类型时,不需要使用类型的具体功能时,只使用Object类中的功能。那么可以用 ? 通配符来表未知类型。但是可以通过li变量来进行add() 操作。

综上:数组的类型不可以是类型变量,除非是采用通配符的方式。因为对于通配符的方式,最后取出数据是要做显式的类型转换的。

2. 反射

使用java.util.reflect.Array,可以不使用通配符,而达到泛型数组的效果:

   List<String>[] lsa = (List<String>[])Array.newInstance(ArrayList.class, 4);     //1
   Object o = lsa;
   Object[] oa = (Object[]) o;
   List<String> li = new ArrayList<String>();
   li.add("3");
   / Correct.
   oa[1] = li;
   // Run time error, but cast is explicit.
   String s = lsa[1].get(0);                                                       //2
   System.out.println(s);

可以看到,我们利用了Array.newInstance()生成了泛型数组,这里没有使用任何通配符,在第2处也没有做显式的类型转换,但是在第1处,仍然存在显式类型转换。

3.3 总结

要想使用泛型数组,要求程序员必须执行一次显示的类型转换,也就是将类型检查的问题从编译器交给了程序员。实际上Java的设计者正是此意,在(List<String>[])Array.newInstance(ArrayList.class, 4)处会有一个unchecked warning,正是编译器在提醒程序员:这个地方,我不会帮你做类型检查,你要自己小心!

猜你喜欢

转载自blog.csdn.net/qq_32534441/article/details/83834203