我遇到了以下代码,这是向List
List list = new ArrayList<Integer>();
ListIterator<Integer> litr = null;
list.add("A");
list.add("1");
list.add(5);
litr = list.listIterator();
while(litr.hasNext()){
System.out.println("UIterating " + litr.next());
}
我希望它抛出ClassCastException
,而是将其写入控制台
A
1
5
看起来很奇怪。我试过的时候:
List<Integer> list = new ArrayList<Integer>();
我遇到了编译时错误。
如果有人能解释String
对象如何添加到ArrayList
答案 0 :(得分:4)
您已将新ArrayList分配给无类型列表。通用类型限制不适用于无类型列表,它可以让您在其中放置任何内容。编译器不会跟踪您的无类型List是指使用泛型类型声明的内容。
在任何情况下,这都不会产生ClassCastException,泛型只会影响编译。在运行时
将类型放在列表变量上的情况:
List<Integer> list = new ArrayList<Integer>();
是首选,它应该生成编译器错误,告诉您在集合中输入了错误的类型。
描述遗留,非通用代码和通用代码如何在this article中互操作:
在适当的通用代码中,Collection将始终伴随一个类型参数。当使用像Collection这样的泛型类型而没有类型参数时,它被称为原始类型。
大多数人的第一直觉是,Collection真正意味着
Collection<Object>
。但是,正如我们之前看到的那样,在需要Collection<Part>
的地方传递Collection<Object>
是不安全的。更准确地说,类型Collection表示某种未知类型的集合,就像Collection<?>
一样。但是等等,这也不对!考虑调用
getParts()
,它返回一个Collection。然后将其分配给k,即Collection<Part>
。如果调用的结果是Collection<?>
,则分配将是错误。实际上,分配是合法的,但它会生成未经检查的警告。需要警告,因为事实是编译器无法保证其正确性。我们无法检查
getAssembly()
中的遗留代码,以确保返回的集合确实是一个部件集合。代码中使用的类型是Collection,可以合法地将所有类型的对象插入到这样的集合中。那么,这不应该是一个错误吗?从理论上讲,是的;但实际上,如果通用代码要调用遗留代码,则必须允许这样做。程序员可以自己确定,在这种情况下,赋值是安全的,因为
getAssembly()
的契约表示它返回了一个零件集合,即使类型签名没有显示这一点。
答案 1 :(得分:1)
这是可能的,因为在Java中实现了泛型 - 使用type erasure,并且因为Java支持raw types以便与旧版本的Java(1.4及更早版本)向后兼容。
泛型仅存在于源代码中。编译器使用它们在编译时检查类型,但随后抛弃泛型。在运行时,List<Integer>
只是List
个对象,并且它不知道它是一个只应包含Integer
个对象的列表。
Java支持使用List
等原始类型而不是List<Integer>
,以便与旧版本向后兼容。当您使用原始类型时,正如您在上面的代码中所做的那样,您会收到编译器警告。您不应该在新代码中使用原始类型 - 只有在您需要处理无法更改的旧代码时才使用它们。
原始类型和类型擦除的组合允许您将对象类型放入您不应该放入的列表中。
因为运行时的List
对其元素应该具有的类型一无所知,所以它不会检查任何内容,因此您不会得到ClassCastException
。