第一章:泛型通配符迷局破解:super如何解决List无法赋值给List问题
在Java泛型编程中,一个常见的困惑是为何 `List` 不能直接赋值给 `List`,即使 `Cat` 是 `Animal` 的子类。这源于泛型的不变性(invariance)——Java为了类型安全,默认不允许这种协变赋值。
问题重现
class Animal {}
class Cat extends Animal {}
List<Cat> cats = new ArrayList<>();
List<Animal> animals = cats; // 编译错误!
上述代码会引发编译错误,因为 `List` 并不是 `List` 的子类型。
使用extends与super通配符
Java提供了两种通配符来放宽限制:
? extends T:表示T或其子类,适用于读取场景(生产者)? super T:表示T或其父类,适用于写入场景(消费者)
要将 `List` 赋值给更通用的引用,可借助 `? super Cat`:
List<Cat> cats = new ArrayList<>();
List<? super Cat> superList = cats; // 合法
superList.add(new Cat()); // 可安全添加Cat实例
此时,`superList` 可接受任何容纳 `Cat` 及其父类型的列表,确保了类型安全性。
PECS原则的应用
遵循“Producer-Extends, Consumer-Super”(PECS)原则:
| 场景 | 通配符 | 用途 |
|---|
| 从集合读取 | ? extends T | 作为数据源 |
| 向集合写入 | ? super T | 作为数据目标 |
通过合理使用 `super` 通配符,不仅能解决赋值问题,还能保障泛型集合在继承体系中的灵活与安全操作。
第二章:Java泛型基础与协变逆变困境
2.1 泛型类型安全机制的核心原理
泛型通过在编译期进行类型检查,确保类型安全,避免运行时类型转换异常。其核心在于类型参数化,将类型作为参数传递,使算法与数据类型解耦。
类型擦除与编译期检查
Java 泛型在编译后会进行类型擦除,替换为原始类型或上界类型,但编译器会在调用处插入强制类型转换,并验证类型一致性。
List<String> list = new ArrayList<>();
list.add("Hello");
String s = list.get(0); // 编译器自动插入类型检查
上述代码中,编译器确保仅能添加 String 类型元素,并在获取时无需手动强转,降低 ClassCastException 风险。
类型约束与边界定义
使用
extends 可定义上界,限制泛型类型的继承范围,提升接口可用性:
<T extends Comparable<T>>:要求类型可比较<T extends Number>:限定为数值类型
2.2 List为何不能赋值给List
在面向对象语言如Java中,尽管`Cat`是`Animal`的子类,但`List`并不能赋值给`List`,这源于泛型的不变性(invariance)设计。
类型安全的保障机制
泛型系统为了防止运行时类型错误,禁止这种看似合理的赋值。例如:
List<Cat> cats = new ArrayList<>();
List<Animal> animals = cats; // 编译错误!
animals.add(new Dog()); // 若允许,将破坏类型安全
若上述代码被允许,`animals`引用可添加任意`Animal`子类(如`Dog`),导致原本只应包含`Cat`的列表被污染,违反泛型契约。
解决方案:使用通配符
通过引入上界通配符可实现安全读取:
List<? extends Animal> 表示可以接受任何Animal子类型的列表- 支持协变读取,但限制写入以保证类型安全
2.3 数组协变与泛型不变的对比分析
数组协变的运行时特性
Java 中数组是协变的,即若 `String` 是 `Object` 的子类型,则 `String[]` 也是 `Object[]` 的子类型。这种设计允许以下赋值:
String[] strings = new String[3];
Object[] objects = strings; // 合法:数组协变
objects[0] = "Hello"; // 合法:存入字符串
objects[1] = new Integer(1); // 运行时抛出 ArrayStoreException
尽管类型系统在编译期允许该操作,但 JVM 在运行时会强制检查数组元素的实际类型,确保类型安全。
泛型的不变性设计
与数组不同,Java 泛型采用不变性(invariance)。例如,`List` 和 `List