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


















