通用列表数组

我正在玩通用和数组,似乎下面的代码编译好,

ArrayList<Key> a = new ArrayList<Key>(); 

但编译器抱怨这个,

 ArrayList<Key>[] a = new ArrayList<Key>[10]; 

通过阅读post在stackoverflow,我有点理解,这是由于types擦除,我可以解决它通过使用,

 ArrayList<Key>[] a = (ArrayList<Key> []) new ArrayList[10]; 

或列表的列表

 ArrayList<ArrayList<Key>> b = new ArrayList<ArrayList<Key>>(); 

但我无法弄清楚幕后的原因。 特别是,为什么第二个是非法的,因为第一个是非常好的。 为什么编译器不会抱怨列表的列表。

你不能有一个数组,因为一个数组需要一个原始types。 你在第二个实例中对它进行了types转换,这使得它符合定义的types,因此是合法的(但是,这是不可能的)。 列表的列表是合法的, ArrayList不是一个数组。

阅读官方教程中的第7.3章(第15页),了解更多细节。

数组对象的组件types可能不是typesvariables或参数化types,除非它是(无界)通配符types。可以声明其元素types为typesvariables或参数化types的数组types,但不能声明数组对象。 可以肯定的是,这很烦人。 这个限制是必要的,以避免如下情况:

 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 

如果允许参数化types的数组,那么上面的例子可以在没有任何未经检查的警告的情况下进行编译,但是在运行时会失败。

教程然后继续说:

由于typesvariables在运行时不存在,因此无法确定实际的数组types是什么。 解决这些限制的方法是使用类文字作为运行时types的标记

我自己也有类似的问题 – FWIW,我没有find有说服力的答案。 从最详细的答案(指PDF参考)的相关部分是这样的:

数组对象的组件types可能不是typesvariables或参数化types,除非它是(无界)通配符types。可以声明其元素types为typesvariables或参数化types的数组types,但不能声明数组对象。 可以肯定的是,这很烦人。 这个限制是必要的,以避免像

  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 

因此,因为我可以捕获List []到Object [],然后将不正确的东西推到Object []中,然后从List引用错误地引用,通过铸造的ref,这是坏/不允许的? 但只有新的?

对于我来说,用新的方式来说明这个问题,多less还是比用法还要less,还是盯着它,希望它开始有意义,或者至lessparsing成漂亮的3d图像。

arrays是穷人的generics; 与真正的generics,应该避免arrays,虽然并不总是可能的。

数组是协变的,generics是不变的; 加上删除,事情就不太好,正如克里斯的答案中的例子所示。

但是我认为可以放宽规范来允许通用数组的创build – 这里真的没有问题。 上阵时危险到来; 那么编译器警告就足够了。

实际上Java确实为可变参数方法创build了通用数组,所以这有点虚伪。

这是利用这个事实的效用方法

 @SafeVarargs static <E> E[] arrayLiteral(E... array) { return array; } @SafeVarargs static <E> E[] newArray(int length, E... array) { return Arrays.copyOf(array, length); } // usage List<String>[] array1 = arrayLiteral(list, list); List<String>[] array2 = newArray(10); 

创build通用数组不是types安全的(请参阅Joshua Bloch的“Effective Java – second edition”中的“项目25:首选列表到数组”)。

使用:

  List<List<Key>> b = new ArrayList<List<Key>>(10); 

或者用Java SE 7:

  List<List<Key>> b = new ArrayList<>(10); 

数组允许转义types检查(如Chris的答案所示)。 所以,你可以有一个通过所有编译器检查的代码(编译器没有“未经检查”的警告),但是在运行时ClassCastException失败。 禁止这种构造会给开发者带来问题,所以警告就会出现。