为什么这个列表不抛出 ClassCastException?

Why doesn't this list throw a ClassCastException?

给定以下 class 结构:

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

您的 dogs 变量属于 List 类型,即 raw 类型。 不是类型List<Dog>

并且由于它是原始类型,您可以向其中添加任何对象。您的 Cat 实例未转换为任何内容。

泛型仅提供编译时安全和检查,不在运行时使用。

阅读 Java Language Specification 4.8. Raw Types 中有关原始类型的更多信息。

对于编译器,List dogs 等同于 List<Object> dogs,因此编译器接受添加任何类型的实例。

注意,编译器考虑的列表类型是原始类型List局部变量左侧的类型赋值),即使右侧使用 Dog 参数创建了泛型类型的实例。

运行 时不保留泛型。所以 ArrayList<Dog> 就是 ArrayList。这就是为什么在 运行 时间不能抛出异常。如果您没有使用原始类型 List.

,编译器可能会在编译时发现此错误