正如Jon post的回答所说,如果编译器允许这个演员(如下所示),以后添加一些其他对象对程序来说可能是件坏事。
ArrayList<String> temList = new ArrayList<String>();
ArrayList<Object> obList = (ArrayList<Object>)temList;//compile error
//obList.add(1); --bad
但令我困惑的是,为什么在同样的情况下,数组会有不同的行为。
String[] strings = new String[10];
Object[] temp = (Object[])strings;//nothing happens
那么有人可以解释这里的差异以及为什么java会做出如此设计的原因?感谢。
修改:一个类似的question
答案 0 :(得分:1)
数组不是100%的对象,它们是平凡的对象。但ArrayList
是一个100%的对象。
如果您尝试将一个Integer分配给临时数组,它将抛出一个ArrayStoreException
。
所以投射阵列很好。
但是将ArrayList
转换为超级对象,其中底层ArrayList实现只能包含String(子类)将在运行时期间导致问题。
感谢Generics,编译器可以在它发生之前识别它并且可以显示编译器错误。如果程序在运行期间失败,这是一个很好的设计。
Java 1.5 Generics之前
List list = new ArrayList();
list.add(1);
list.add("One");
list.add(100l);
合法人员必须进行大量instanceof
检查。他们未能检查程序在运行时崩溃的地方。
答案 1 :(得分:0)
如果数组的组件类型可分配给指定数组的组件类型,则设计数组以允许协变分配。类型检查在运行时由JVM完成,其中如果尝试将值存储在不兼容的数组中,则抛出ArrayStoreException
。使用正确,这允许表达数组的协变类型,这通常很方便。
但是,这种语言特性可能导致漫反射运行时异常,Sun不希望重复这些异常,因为Java 5引入了泛型类型赋值。相反,Sun希望在编译时发现这种无效使用。这似乎特别重要,因为泛型引入了比数组类型更复杂的类型系统组件,因此如果Sun决定采用不同的方式,类似于ArrayStoreException
的运行时错误肯定会变得更加常见。相反,对于泛型,通配符解决了协方差和逆变问题,这些通配符允许在编译时而不是运行时发现类型错误。