给出以下类结构:
class Animal {}
class Dog extends Animal {}
class Cat extends Animal {}
仅在初始化时使用泛型创建列表,而不是在引用上创建列表:
List dogs = new ArrayList<Dog>();
为什么此代码不会生成ClassCastException?
dogs.add(new Cat()); // How is Cat casted to Dog??!
Cat cat = (Cat) dogs.get(0); // Return perfectly valid Cat object.
我知道不存在编译错误,因为list
引用没有任何泛型并且会接受任何Object
。但是,当我尝试添加Cat对象时,为什么JVM不生成任何异常?
答案 0 :(得分:2)
您的dogs
变量属于List
类型,是原始类型。类型List<Dog>
的不。
由于它是原始类型,因此您可以向其添加任何对象。您的Cat
实例不会转换为任何内容。
泛型仅提供编译时安全性和检查,它们不会在运行时使用。
详细了解Java Language Specification 4.8. Raw Types中的原始类型。
答案 1 :(得分:1)
对于编译器,List dogs
等同于List<Object> dogs
,因此编译器接受添加任何类型的实例。
请注意,编译器考虑的列表类型是原始类型List
(赋值左侧的局部变量的类型),即使右侧使用Dog
参数创建泛型类型的实例。
答案 2 :(得分:0)
在运行时不保留泛型。因此ArrayList<Dog>
只是ArrayList
。这就是为什么在运行时不能抛出异常的原因。如果您没有使用原始类型List
,编译器可能在编译时捕获到此错误。