pecs原则是:producer用extends(只读时用上界),consumer用super(只写时用下界);extends对应数据“出口”,super对应数据“入口”,核心在于方法中add和get的操作方向。

记住 PECS 的关键是抓住“动作”和“方向”:谁在往外给数据,谁在往里收数据。不是记单词缩写,而是看方法里对集合做了什么操作。
Producer 用 extends:只读不写时选上界
当一个方法只从泛型集合中取元素(比如遍历、查找、计算总和),它就是生产者——把数据“生产”出来供你用。这时用 ? extends T,保证你能安全地把每个元素当作 T 或其父类来用。
- 能做的事:调用 get()、遍历、返回 T 类型值
- 不能做的事:调用 add()(除 null 外),因为编译器不知道底层到底是 AppleList 还是 BananaList
- 例子:
void printAll(List extends Fruit> fruits)可以接收List<apple></apple>或List<banana></banana>,但不能往里面加新水果
Consumer 用 super:只写不读时选下界
当一个方法只往集合里塞数据(比如批量添加、归并、填充默认值),它就是消费者——把外部数据“消费”进去。这时用 ? super T,保证你能放心地把 T 类型的对象放进去。
- 能做的事:调用 add(T),传入 T 或其子类实例(如 add(new Apple()) 到
List super Fruit>) - 不能做的事:安全地 get() 并当作具体类型使用(比如取出来直接当 Fruit 用会报错,只能当 Object)
- 例子:
void addApples(List super Apple> basket)可以接收List<fruit></fruit>、List<object></object>,甚至List<apple></apple>
混用场景:先分清主次操作
如果一个方法既读又写,通配符往往不合适,优先考虑用具体类型参数(如 <t> void process(List<t> list)</t></t>)。PECS 是为“单向操作”设计的安全边界。强行套用会导致要么读不了,要么写不了。
- 常见误区:想用
List extends Number>来 add(Integer) —— 不行,这是生产者语义 - 正确做法:需要写入就换用
List super Integer>,哪怕你只是临时存一下 - 工具类参考:Collections.copy(dest, src) 中 dest 是 consumer,用
? super T;src 是 producer,用? extends T
一句话口诀辅助记忆
Extends 是“出口”,Super 是“入口”。数据从集合里出来 → extends;数据往集合里进 → super。不用背英文缩写,盯住方法体里那几行 add 和 get 就够了。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











