pecs原则指泛型参数作为生产者(? extends t)时只读、作为消费者(? super t)时只写;collections.copy中dest用? super t、src用? extends t即典型应用。

PECS 原则不是语法口诀,而是对泛型参数“行为角色”的判断:它在当前上下文中是往外提供数据(Producer),还是往里接收数据(Consumer)。用对了,编译器就放行;用反了,立刻报错——不是写法难,是角色没想清。
只读集合时用 ? extends T
当你遍历、取值、处理内容,但不往里加新元素,这个集合就是生产者。
- 声明如 List extends Number>,可安全接收
ArrayList<integer></integer>或LinkedList<double></double> - 能调用
get(),返回值可赋给Number或其父类(如Object) - 禁止调用
add()、set()—— 编译器无法确认容器实际允许哪种子类型
只写集合时用 ? super T
当你不断往里塞数据、做归并、收集结果,且不关心从中读出什么具体类型,这个集合就是消费者。
- 声明如 List super Integer>,可接受
ArrayList<number></number>、ArrayList<object></object>甚至LinkedList<serializable></serializable> - 能安全调用
add(new Integer(42)),因为所有这些容器都保证能装下Integer - 但
get(0)只能赋给Object,不能直接当Integer用——类型太宽,编译器不敢保证
方法参数设计要贴合真实用途
别看类继承关系,盯住方法体里怎么用那个泛型参数。
-
void printFruits(List extends Fruit> fruits)→ 只 for-each 打印,是 Producer -
void putApple(List super Apple> basket)→ 只 add(new Apple()),是 Consumer -
void swap(List<t> list, int i, int j)</t>→ 既要 get 又要 set,就不能用通配符,得用具体类型或泛型方法
标准库里的 PECS 实际例子
Java 集合工具类大量遵循该原则,是学习样板。
-
Collections.copy(dest, src):dest 是消费者 →Collection super T>;src 是生产者 →Collection extends T> -
Collections.addAll(collection, elements...):collection 参数是消费者 →Collection super T> -
Arrays.asList(T...)返回的是List<t></t>,不是通配符——因为要支持读写,必须精确
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











