? super T 是Java中实现写入场景逆变安全的核心机制,它允许向泛型集合添加T及其子类型对象,确保编译期类型安全,但读取时只能返回Object。
在 java 中,? super t 是实现写入场景下逆变安全性的核心机制。它不改变泛型本身的不变性,而是通过编译期类型约束,在“能往里放什么”这件事上给出精确、安全的边界。
什么是逆变安全性?
逆变(Contravariance)指:当 T 是 S 的子类型时,C<s></s> 可以被视为 C<t></t> 的子类型——这与协变方向相反。Java 泛型默认不变,但 ? super T 模拟了这种逆变行为,专用于“接收数据”的消费者(Consumer)场景。
例如:List super Integer> 可安全指向 List<integer></integer>、List<number></number> 或 List<object></object>,因为三者都能容纳 Integer 实例。这就是逆变的安全体现:更宽泛的容器类型,反而能接受更具体的元素。
写入操作为何安全?
编译器只允许向 ? super T 集合中添加 T 或其子类型的对象,原因如下:
- 目标集合的实际类型一定是
T的某个超类(如Number、Object),而T及其子类天然可向上转型,赋值无风险 - 编译器在擦除前完成类型检查,确保所有
add()调用都满足“参数 ≤ 实际类型”的关系 - 运行时虽无泛型信息,但擦除后底层是原始类型(如
List),而Integer、Double等均可作为Object存入,不会触发ArrayStoreException
读取操作为何受限?
从 List super Integer> 中调用 get(0),返回类型只能是 Object,不能是 Integer 或 Number,因为:
当用户要求为 Java 代码添加注释、修改注释、审查注释、整理注释格式,或要求按照代码注释规范处理 Java 文件时,使用本技能。本技能用于统一生成和维护 Java 类注释模板、按 Git 对比 release 判断版本号、补充每行代码上方中文块注释、调整注释空行规则,并保持 Java 文件 UTF-8 无 BOM 编码。典型触发场景包括:补充类注释、更新 @version、检查 @author 来源、整理行尾注释、把注释放到代码上一行、检查注释是否符合规范、构建前检查 Java 注释风格。
立即学习“Java免费学习笔记(深入)”;
- 实际引用的可能是
List<object></object>,里面存的也许是String或Thread - 编译器只知道“下界是
Integer”,但不知道“上界是什么”,无法推断出统一的具体返回类型 - 若允许返回
Integer,就可能在运行时发生ClassCastException,破坏类型安全
典型应用:遵循 PECS 原则的工具方法
真正发挥 ? super T 价值的,是设计通用的消费型方法:
-
Collections.copy(List extends T> src, List super T> dest):源列表产出T,目标列表消费T -
Stream<t>.forEach(Consumer super T> action)</t>:动作可处理T或其任意父类(如传入Consumer<object></object>也合法) - 自定义收集方法:
public static <t> void addAll(List super T> list, T... elements)</t>
这些设计让方法签名更宽松,调用方无需为每种子类型单独重载,同时杜绝了运行时类型错误。

















