我有以下测试代码。我正在努力理解Generics和legacy之间的互操作性。
List myList = new ArrayList();
myList.add("abc");
myList.add(1);
myList.add(new Object());
System.out.println("Printing the unchecked list");
Iterator iterator = myList.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
List<String> strings = myList;
System.out.println("Printing the unchecked list assigned to List<String> using iterator");
Iterator stringIterator = strings.iterator();
while (stringIterator.hasNext()) {
System.out.println(stringIterator.next()); // this works fine! why? shouldn't it fail converting the 1 (int/Integer) to String?
}
System.out.println("Printing the unchecked list assigned to List<String> using for");
for (int i = 0; i != strings.size(); i++) {
System.out.println(strings.get(i)); // blows up as expected in the second element, why?
}
System.out.println("Printing the unchecked list assigned to List<String> using foreach");
for (String s : strings) {
System.out.println(s); // blows up as expected in the second element, why?
}
为什么当我尝试打印iterator.next
时,它工作得很好,而当我使用for
循环迭代时,System.out.println
会像预期的那样爆炸?
关于泛型,需要记住的关键是它只是一种从源代码中省略强制转换的方法。强制转换由编译器插入。因此,由于存在(或不存在(强制转换,代码会失败(或不会失败(。
- 这很好用!为什么
因为stringIterator
是原始的,所以stringIterator.next()
不会强制转换为任何内容:它只是读作Object
,这是已擦除的返回类型。
- 在第二个元素中按预期爆炸,为什么
strings
是List<String>
,因此假定strings.get(i)
的结果为String
,并选择调用println(String)
,而不是println(Object)
。因此,将插入一个铸件。strings.get(1)
不是String
,因此使用ClassCastException
会失败。
有趣的是,如果您使用List<Integer>
尝试此操作,则不会失败,因为会调用println(Object)
,并且不需要强制转换。
- 在第二个元素中按预期爆炸,为什么
因为插入了对String
的强制转换,所以要将元素分配给String s
。
关于增强型for回路的减温形式,请参阅JLS 14.14.2:
for (I #i = Expression.iterator(); #i.hasNext(); ) { {VariableModifier} TargetType Identifier = (TargetType) #i.next(); Statement }
因此,您的代码等效于:
for (Iterator<String> it = strings.iterator(); it.hasNext(); ) {
String s = (String) it.next(); // Actually, your code fails on this line.
System.out.println(s);
}