? super t 是下界通配符,表示实际类型为 t 或其任意父类(含接口);允许安全写入 t 及其子类实例,读取仅返回 object,体现 pecs 原则中“consumer super”的设计思想。

Java 中的 ? super T 是下界通配符,它的“下限”不是指类型要“大于等于 T”,而是说实际类型必须是 T 本身或它的任意父类(包括接口)。限制的关键不在于“能用哪些类型声明”,而在于“编译器允许你对这个集合做什么操作”——它通过收紧读取能力、放开写入边界来保障类型安全。
什么是 ? super T 的合法实际类型
声明 List super Integer>,可指向以下具体列表:
-
new ArrayList<integer>()</integer>(T 本身) -
new ArrayList<number>()</number>(Integer 的直接父类) -
new ArrayList<object>()</object>(最顶层父类) -
new ArrayList<serializable>()</serializable>(Integer 实现的接口)
但不能指向 ArrayList<string></string> 或 ArrayList<double></double>——它们与 Integer 无继承关系,不满足“是 Integer 或其父类”的约束。
写入:只允许添加 T 及其子类实例
你可以安全地向 List super Integer> 添加 Integer、int(自动装箱)、或任何 Integer 子类(虽然 Integer 是 final,但逻辑上成立)。这是因为所有目标容器(Number、Object 等)都一定能容纳 Integer。
Java Maven 项目审查工作流的通用输入处理。当 Java Maven 项目以 ZIP压缩包或 GitLab 仓库 URL 形式提供且需要...时使用。
- ✅
list.add(42)—— 合法 - ✅
list.add(new Integer(100))—— 合法 - ❌
list.add(3.14)—— 编译失败:Double 不是 Integer 的子类,也不满足下界要求 - ❌
list.add(new Number())—— 编译失败:Number 是父类,但实际容器可能是ArrayList<integer></integer>,无法存入更宽泛的父类实例
读取:只能得到 Object,无法安全转成 T
因为编译器只知道元素类型 ≥ T(即至少是 T 的父类),但不知道具体是哪一个。所以 get(0) 的返回类型被擦除为 Object:
- ✅
Object obj = list.get(0);—— 安全 - ❌
Integer i = list.get(0);—— 编译错误,类型不匹配 - ⚠️ 强制转换如
(Integer) list.get(0)可能运行时抛ClassCastException,不推荐
为什么这样设计?核心是 PECS 原则
它不是为了“描述容器里有什么”,而是为了明确“你要用它干什么”:
- 如果你往里塞数据(消费者角色),用
? super T—— 写入安全,类型向上兼容 - 如果你从里取数据(生产者角色),该用
? extends T—— 读取安全,类型向下兼容 - 如果既读又写,通常说明泛型参数设计不合理,应回退到具体类型
T或重构接口
这种限制看似苛刻,实则是编译期守住类型安全的必要代价。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










