public class Test {
public static void main(String[] args) {
ArrayList<XiaoMi> xiaoMiList = new ArrayList<XiaoMi>();
ArrayList<BYD> bydList = new ArrayList<BYD>();
run(xiaoMiList); //错误使用
}
public static void run(ArrayList<Car> list) {
// 汽车跑的逻辑
System.out.println("the car runs fast");
}
}
疑问:xiaoMiList中的每个元素都是Car的子类,为什么不能使用多态的方式实现将ArrayList传给ArrayList呢
java中的协变
在Java中,协变是指一个类型的子类型可以被当作其父类型来使用。例如,如果 XiaoMi 是 Car 的子类,那么 XiaoMi 的对象可以被当作 Car 的对象来使用。这是Java语言设计中的一项重要特性,它支持面向对象编程中的多态性。
数组列表与协变
然而,尽管Java中的基本类型和引用类型支持协变,ArrayList 却不支持协变。这是因为 ArrayList 的设计考虑到了类型安全性和避免潜在的运行时错误。
设计思想
Java中泛型擦除
1. 类型安全性:
Java的设计目标之一是保证类型安全性。如果 ArrayList<XiaoMi> 能够被当作 ArrayList<Car> 使用,那么可能会发生以下情况:
* 可能意外地向 ArrayList<XiaoMi> 中添加了一个 BYD 对象,因为 BYD 也是 Car 的子类。
* 这种操作在编译时是合法的,但在运行时会导致 ClassCastException,因为 ArrayList<XiaoMi> 实际上只能存储 XiaoMi 对象。
2. 泛型擦除:
Java中的泛型是基于类型擦除实现的。这意味着在编译时类型参数被替换为其实现的原始类型(例如 ArrayList<XiaoMi> 在运行时实际上就是 ArrayList<Object>),而在运行时类型参数的信息被丢弃。
如果 ArrayList<XiaoMi> 能够被当作 ArrayList<Car> 使用,那么编译器无法保证类型安全,因为它不知道 XiaoMi 是否是 Car 的子类。