? 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 或其子类型的对象,原因如下:
Java Maven 项目审查工作流的通用输入处理。当 Java Maven 项目以 ZIP压缩包或 GitLab 仓库 URL 形式提供且需要...时使用。
- 目标集合的实际类型一定是
T的某个超类(如Number、Object),而T及其子类天然可向上转型,赋值无风险 - 编译器在擦除前完成类型检查,确保所有
add()调用都满足“参数 ≤ 实际类型”的关系 - 运行时虽无泛型信息,但擦除后底层是原始类型(如
List),而Integer、Double等均可作为Object存入,不会触发ArrayStoreException
读取操作为何受限?
从 List super Integer> 中调用 get(0),返回类型只能是 Object,不能是 Integer 或 Number,因为:
- 实际引用的可能是
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>
这些设计让方法签名更宽松,调用方无需为每种子类型单独重载,同时杜绝了运行时类型错误。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










