为什么这个列表不抛出 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
.
,编译器可能会在编译时发现此错误
给定以下 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
.