逆变是java泛型编译期类型安全策略,体现为list

什么是逆变,它和 List super T> 有什么关系
逆变(Contravariance)不是 Java 泛型的运行时行为,而是类型系统在编译期对通配符的一种安全设计策略。它体现在 ? super T 这种写法上:表示“接受 T 或其任意父类”,即类型边界向下放宽(往继承链上游走)。这种放宽不是为了兼容运行时多态,而是为了让方法参数能接收更宽泛的容器类型,同时保证写入操作类型安全——这正是逆变的核心价值。
为什么可以安全添加 T 类型的元素
因为编译器知道:List super T> 底层实际引用的集合,其元素类型至少是 T 的某个父类(比如 Object、Number、Comparable 等)。而 T 本身一定能被赋值给它的任何父类,所以向其中 add(T) 是类型安全的。
-
例如:List super Integer> 可能指向 List
或 List
为什么读取时只能得到 Object 类型
读取操作面临的是不确定性:你不知道这个 List super T> 实际装的是 T 的哪个父类。可能是 Number,也可能是 Comparable,甚至是 Object —— 它们没有共同的非 Object 上界。为避免类型泄露,Java 强制返回类型为 Object。
- list.get(0) 的返回类型只能是 Object,不能是 T,也不能是 Number
- 即使你知道底层是 List
,编译器也不允许你直接 (Number) list.get(0),因为调用方声明的是 ? super Integer,语义上不承诺可读出 Number - 这是类型安全的保守策略:宁可丢失精度,也不允许潜在的 ClassCastException
它和 extends T 的对比很说明问题
? extends T 和 ? super T 是一对镜像设计,分别服务不同场景:
- ? extends T:你能 get() 出 T(或其子类),但不能 add() 任何东西(null 除外)——适合做数据生产者
- ? super T:你能 add(T) 或其子类,但 get() 只能得 Object——适合做数据消费者
- 这就是 PECS 原则:Producer-Extends,Consumer-Super










