编译器可以自发地进行转换,他们只是规定不因为通用阵列不能表现像非泛型数组。
参见10.5. Array Store Exception:
对于数组类型为A[]
,其中A
是引用类型,分配到该阵列的一个组件在运行时进行检查,以确保所分配的值是分配到组件。
如果所分配的值的类型与组件类型不是分配兼容的,则会引发ArrayStoreException
。
如果数组的组件类型不可确定,则Java虚拟机无法执行上一段中描述的存储检查。这就是为什么禁止使用不可指定元素类型的数组创建表达式的原因。
如果我们把一些其他种类的List
在它List<MyDTO>[]
不会丢,所以它不表现为一个数组。请注意报价中的最后一句:“这就是为什么禁止使用不可指定元素类型的数组创建表达式。”这就是原因,它被指定为这样。 (而且,备案,this reasoning has always existed,所以它是存在,当这个问题被张贴在2011年)
我们仍然可以做到这一点:
@SuppressWarnings({"unchecked","rawtypes"})
List<MyDTO>[] dtoLists = new List[] {
new ArrayList<MyDTO>(), anExistingDtoList
};
或者这样:
@SuppressWarnings("unchecked")
List<MyDTO>[] dtoLists = (List<MyDTO>[]) new List<?>[] {
new ArrayList<MyDTO>(), anExistingDtoList
};
(除了静态地检查参数类型之外,可变参数的东西是等价的:它可以是creates a List[]
和suppresses warnings。)
现在,当然,规范可以改变“如果所分配的值的类型与的原始类型的元件类型...”不是分配兼容的,但是要点是什么?它会在一些不寻常的情况下保存少数人物,但是否则会禁止那些不了解其含义的人发出警告。
此外,我看到the tutorial和其他典型解释没有证明的是如何烘焙到类型系统协变阵列。
例如,给出如下声明:
// (declaring our own because Arrays.fill is defined as
// void fill(Object[], Object)
// so the next examples would more obviously pass)
static <T> void fill(T[] arr, T elem) {
Arrays.fill(arr, elem);
}
你知道,这个编译?
// throws ArrayStoreException
fill(new String[1], new Integer(0));
而这个编译过:
static <T, U extends T> void fill(T[] arr, U elem) {...}
但是,这只是一个:
// doesn't throw ArrayStoreException
fill(dtoLists, new ArrayList<Float>());
的Java 8之前,我们可以到fill
失败给它下面的声明使这些电话类型推断问题,现在它工作“正确”,一味地将List<Float>
放入List<MyDTO>[]
。
这叫做堆污染。它可能会导致ClassCastException
在某个时间后抛出,可能与实际导致问题的操作完全无关。像List
这样的通用容器造成的堆污染需要更加明显的不安全行为,例如使用raw types,但在这里,我们可以隐式导致堆污染,并且不会有任何警告。
通用数组(通常是数组)实际上只允许我们在最简单的情况下进行静态检查。
因此很明显,语言设计者认为最好不要让他们,而了解他们存在问题的程序员可以抑制警告并绕过限制。
[Array of Generic List](http://stackoverflow.com/questions/7810074/array-of-generic-list) – Thilo
的可能重复检查出该重复的最佳答案。它有一个例子,为什么这是不被允许的。 – Thilo
这不是重复的。我的问题要求有关编译器设计问题的答案。 –