第一章:泛型 super 通配符的写入限制
在 Java 泛型编程中,`super` 通配符(即 ``)用于限定泛型参数的下界,表示接受类型 `T` 或其任意超类。这种通配符常用于支持协变操作,尤其是在集合写入场景中。然而,尽管 `` 允许向容器中添加 `T` 类型的对象,它对读取操作施加了严格的限制。
通配符的使用场景
- 适用于需要向泛型容器写入数据的方法
- 常见于工具方法,如
Collections.addAll() - 不能安全地读取返回值的具体类型
代码示例与说明
// 声明一个只能写入 Number 或其子类的列表
List list = new ArrayList();
// 合法:可以添加 Integer 及其子类
list.add(42);
list.add(Integer.valueOf(10));
// 非法:无法确定返回的具体类型,编译错误
// Integer num = list.get(0); // ❌ 编译失败
// 只能以 Object 类型接收
Object obj = list.get(0); // ✅ 合法,但失去类型信息
上述代码展示了 `super` 通配符的核心特性:**写入安全,读取受限**。由于通配符掩盖了实际的泛型类型,编译器无法保证从集合中读取的元素是何种具体类型,因此只能以
Object 形式返回。
读写能力对比表
| 操作 | 是否允许 | 说明 |
|---|
| add(T item) | ✅ 是 | 可安全写入 T 类型对象 |
| get(int index) | ⚠️ 仅限 Object | 返回类型为 Object,需强制转型 |
| set(int index, T item) | ✅ 是 | 允许替换元素 |
该机制的设计遵循“生产者-消费者”原则中的“消费者”模式——即主要用于接收数据的结构。开发者应合理利用此特性,在设计 API 时明确泛型边界的意图,避免类型系统被破坏。
第二章:理解 ? super T 的核心机制
2.1 协变与逆变中的类型安全原则
在类型系统中,协变(Covariance)与逆变(Contravariance)决定了子类型关系在复杂类型中的传递方式。正确应用这些规则是保障类型安全的关键。
协变:保持子类型方向
当泛型结构保持子类型关系时,称为协变。例如,在函数返回值中允许子类替代父类:
type Animal struct{}
type Dog struct{ Animal }
func GetAnimal() *Animal { return &Dog{} } // 协变允许
该代码合法,因
*Dog可安全替代
*Animal,符合“生产者”场景的类型安全。
逆变:反转子类型方向
参数位置常需逆变,即若
B是
A的子类型,则函数接收
A的可接受更宽泛的输入。
| 变型类型 | 适用位置 | 安全性依据 |
|---|
| 协变 | 返回值、只读集合 | 产出更具体的值更安全 |
| 逆变 | 函数参数 | 接受更通用的输入更安全 |
2.2 ? super T 的类型边界定义与推导
在泛型编程中,`? super T` 表示一种下界通配符(lower bounded wildcard),用于限定泛型参数的类型必须是 `T` 或其任意父类型。这种机制常用于支持写入操作的场景,确保类型安全。
类型边界的语义解析
`? super T` 允许接受 `T` 类型或其所有超类的实例。例如,`List` 可以引用 `List`、`List` 或 `List