为什么这个列表没有抛出ClassCastException?

时间:2015-01-21 12:46:03

标签: java generics classcastexception

给出以下类结构:

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不生成任何异常?

3 个答案:

答案 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,编译器可能在编译时捕获到此错误。