? super t 表示类型至少是t或其父类,允许安全写入t及子类对象,但读取只能得到object;它用于消费者场景,体现pecs原则中的“consumer super”。

? super T 是 Java 泛型中用于限定类型下界的通配符,表示“某个未知类型,但它至少是 T 或 T 的任意父类”。它不指定具体类型,而是划出一个**最低兼容门槛**:实际类型不能比 T 更“窄”,但可以更“宽”(如 Object、Number、Serializable 等)。
它怎么限制下界?关键在“至少是 T”
编译器只保证该泛型结构能安全容纳 T 类型的对象——因为 T 可以无条件赋值给它的任何父类型。所以:
-
List super Integer>可以引用ArrayList<integer></integer>、ArrayList<number></number>或ArrayList<object></object> - 但不能引用
ArrayList<long></long>或ArrayList<string></string>,因为它们与Integer没有父子关系 - 这个“下界”不是说类型必须是
Integer,而是说类型不能低于Integer—— 即不能是Integer的子类(Java 中Integer是 final,但原理通用)
为什么只能写入 T,不能安全读取为 T?
因为编译器只知道元素类型 ≥ T,但不知道具体是什么。比如 List super Animal> 可能是 List<animal></animal>,也可能是 List<object></object>,甚至 List<serializable></serializable>(如果 Animal 实现了它)。所以:
-
add(new Dog())✅ 安全:任何Dog都可赋给Animal、Object、Serializable -
get(0)→ 返回类型是Object,只能赋给Object或其父类(实际几乎总是Object) -
Animal a = list.get(0);❌ 编译失败:无法保证返回的是Animal,万一底层是List<object></object>,里面存了String呢?
典型使用场景:消费者(Consumer)操作
它天然适配“往里塞数据”的需求,尤其在工具方法中提升复用性:
-
public static <t> void copy(List extends T> src, List super T> dest)</t>:源列表生产T,目标列表消费T -
public static <t> void addAll(List super T> list, T... items)</t>:向任意足够“宽”的容器添加T实例 - 传入
ArrayList<object></object>、LinkedList<animal></animal>、Stack<serializable></serializable>都合法,只要它们能装下T
和 ? extends T 的核心区别
二者服务于相反角色,不可互换:
-
? extends T:上界通配符,“最多是T”,适合读取(Producer),不能安全写入(除null) -
? super T:下界通配符,“至少是T”,适合写入(Consumer),读取只能得Object - 这就是 PECS 原则:Producer-Extends,Consumer-Super
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











