通用列表数组
我正在玩通用和数组,似乎下面的代码编译好,
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失败。 禁止这种构造会给开发者带来问题,所以警告就会出现。
- 如何从List <>投射ArrayList <>
- 什么原因导致javac发出“使用未经检查或不安全的操作”警告
- 使用通用方法实现接口
- Javagenerics – types擦除 – 何时发生
- 在C#中,为什么List <string>对象不能存储在List <object>variables中
- 为什么java.util.Properties实现Map <Object,Object>而不是Map <String,String>
- 如何创build一个通用的扩展方法?
- 将Hibernate Query.list()转换为List <Type>的“正确”方法是什么?
- generics返回types的上界 – 接口与类 – 令人惊讶的有效的代码