Java 用类型擦除欺骗集合
我试图举例说明类型擦除来向某人解释它,但我发现了一些意想不到的事情。以下是我尝试过的片段:Java 用类型擦除欺骗集合,java,casting,type-erasure,Java,Casting,Type Erasure,我试图举例说明类型擦除来向某人解释它,但我发现了一些意想不到的事情。以下是我尝试过的片段: Object o = new ArrayList<Integer>(); List<String> list = (List<String>) o; list.add("Oups"); System.out.println(list); 哪个会引发异常(ArrayStoreException)?(由于问题的更改而更新。) 最后一行不会抛出异常,因为ArrayList的
Object o = new ArrayList<Integer>();
List<String> list = (List<String>) o;
list.add("Oups");
System.out.println(list);
哪个会引发异常(ArrayStoreException
)?(由于问题的更改而更新。)
最后一行不会抛出异常,因为ArrayList
的toString()
实现根本不关心元素类型。它简单地对存储在其内部对象[]
元素数组中的每个对象递归调用toString()
,因此不需要检查其元素的运行时类型
但是,该代码实际上也不会失败:
List<Integer> il = new ArrayList<Integer>();
Object o = il;
List<String> sl = (List<String>)o;
sl.add("Oups");
System.out.println(il.get(0));
因为现在您正在执行一个操作,该操作假定元素是一个整数
,并且转换包含在生成的代码中
另一方面,基元数组具有其元素类型的运行时知识,并将在每次插入时断言它。(由于问题的更改而更新。)
最后一行不会抛出异常,因为ArrayList
的toString()
实现根本不关心元素类型。它简单地对存储在其内部对象[]
元素数组中的每个对象递归调用toString()
,因此不需要检查其元素的运行时类型
但是,该代码实际上也不会失败:
List<Integer> il = new ArrayList<Integer>();
Object o = il;
List<String> sl = (List<String>)o;
sl.add("Oups");
System.out.println(il.get(0));
因为现在您正在执行一个操作,该操作假定元素是一个整数
,并且转换包含在生成的代码中
另一方面,基元数组在运行时知道其元素类型,并且在每次插入时都会断言它。由于运行时的类型擦除,它的类型是
对象,并且您的列表是空的,您从不迭代它
List<Integer> o = new ArrayList<Integer>();
List<String> list = (List<String>) (Object) o;
list.add("Oups");
for (Integer i : o) { // <-- Iterate the List<Integer>
System.out.println(i);
}
由于运行时的类型擦除,它的类型是Object
,并且您的列表是空的,并且您从不迭代它
List<Integer> o = new ArrayList<Integer>();
List<String> list = (List<String>) (Object) o;
list.add("Oups");
for (Integer i : o) { // <-- Iterate the List<Integer>
System.out.println(i);
}
ArrayList
中的数组是一个对象[]
,而不是一个整数
,因此为其分配任何任意对象都没有问题。当您尝试执行list.get(0)
时,它将中断,因为编译器将插入一个隐式转换,(Integer)list.get(0)
,该转换将失败
(这是堆污染是一个严重缺陷的原因之一;故障可能发生在远离实际存在缺陷的代码的地方。)数组列表中的数组是一个对象[]
,而不是整数
,因此为其分配任何任意对象都没有问题。当您尝试执行list.get(0)
时,它将中断,因为编译器将插入一个隐式转换,(Integer)list.get(0)
,该转换将失败
(这就是堆污染是一个令人讨厌的bug的原因之一;失败可能发生在远离实际bug的代码的地方。)我当时应该包括真正的最后一行,这是列表的打印。我会更新我的帖子。为什么打印列表不会导致抛出异常?添加“真正的最后一行”显然使问题大不相同,因此我完全修改了答案:谢谢你的回答;)我当时应该包括真正的最后一行,那是列表的打印件。我会更新我的帖子。为什么打印列表不会导致抛出异常?添加“真正的最后一行”显然使问题大不相同,因此我完全修改了答案:谢谢你的回答;)我还尝试了一个填充的列表
,忘了提及我的阅读。哈哈,我已经阅读了文档的这一部分,因为上面有很多问题,但我似乎已经记住,在这种情况下,强制转换不会引发异常,而插入会引发异常。我现在明白了数组和泛型之间的混淆,因为Integer[]
和String[]
实际上是两个不同的类,而List
和List
至少在Java@Dici对于数组的情况,我可以参考并指出数组扩展了Object
(它们是实例)。我还尝试了填充的列表
,忘了提及itRead about。哈哈,我已经阅读了文档的这一部分,因为上面有很多问题,但我似乎已经记住,在这种情况下,强制转换不会引发异常,而插入会引发异常。我现在知道这是数组之间的混淆nd泛型,因为Integer[]
和String[]
实际上是两个不同的类,而List
和List
至少在Java@Dici对于数组的情况,我可以参考并指出数组扩展了Object
(它们是实例)。
Exception in thread "main" java.lang.ClassCastException:
java.lang.String cannot be cast to java.lang.Integer