pecs原则指producer extends、consumer super:? extends t用于只读场景(如遍历、求和),可get()为t但不可add();? super t用于只写场景(如添加、收集),可add(t)但get()仅返回object。

理解 ? extends T 和 ? super T 的关键,不在于死记语法,而在于抓住它们背后的数据流向——也就是 PECS 原则:Producer Extends,Consumer Super。
什么是 PECS 原则
PECS 是 Java 泛型设计中一条被官方反复验证、广泛推荐的经验法则:
-
Producer(生产者)用
? extends T:集合只负责“往外提供”元素,比如遍历、读取、计算总和; -
Consumer(消费者)用
? super T:集合只负责“往里接收”元素,比如添加、填充、收集数据。
这个原则直接对应类型系统的协变(covariant)与逆变(contravariant)逻辑,也解释了为什么一个通配符能读不能写,另一个能写不能读。
? extends T:适合读取的上界通配符
它表示“某个未知类型,但一定是 T 或它的子类”。例如 List extends Number> 可以是 List<integer></integer>、List<double></double>,甚至 List<number></number>。
- ✅ 允许调用
get(),返回值可安全转为T(如Number n = list.get(0);); - ❌ 禁止调用
add()(除了null),因为编译器无法确认你加进去的Integer是否符合当前实际类型(可能是List<double></double>); - 典型场景:统计一组数字的平均值、查找最大值、打印所有元素。
? super T:适合写入的下界通配符
它表示“某个未知类型,但一定是 T 或它的父类”。例如 List super Integer> 可以是 List<integer></integer>、List<number></number> 或 List<object></object>。
- ✅ 允许调用
add(T)(如list.add(new Integer(42));),因为任何T都能赋值给其父类型; - ❌
get()只能返回Object(最顶层公共父类),无法安全转成具体子类型; - 典型场景:把一批
Integer收集到通用容器中、实现泛型工具方法如Collections.copy(dest, src)。
对比记忆口诀
记住两句话就能快速判断:
- “要拿东西出来 →
extends”(拿出来的都能当T用); - “要塞东西进去 →
super”(塞进去的T肯定能放进T的父类容器)。
两者不能混用在同一参数位置,也不可用于类或接口的泛型声明(仅限方法参数、变量声明等使用点)。










