PECS原则是泛型集合使用意图的精准表达:只读用? extends T(生产者),只写用? super T(消费者);读写混合应拆分为两个方法,跨层流转时成对使用以保障类型安全与多态兼容性。

PECS 原则不是语法口诀,而是对泛型集合“使用意图”的精准表达:只读就用 ? extends T,只写就用 ? super T;关键不在类继承关系,而在你对这个集合要做什么操作。
只读集合:用 ? extends T(生产者)
当你从集合中取数据、遍历、处理内容,且不往里添加任何元素时,它就是生产者。此时声明为 List extends Fruit>,表示“里面全是 Fruit 或它的子类(如 Apple、Banana),你可以安全地把它们当 Fruit 用”。
- ✅ 允许:调用
get()、iterator().next(),结果可直接赋给Fruit或其父类型(如Object f = list.get(0)) - ❌ 禁止:调用
add()、set()(连new Fruit()都不行),因为编译器无法确认容器实际能接受哪种子类型 - ? 示例:
void printNames(List extends Person> people)可接收List或List,但不能往里加新对象
只写集合:用 ? super T(消费者)
当你向集合中塞数据、批量入库、归并输入,且不关心从中读出的具体类型(或只按 Object 处理)时,它就是消费者。此时声明为 List super Apple>,表示“这个容器至少能装下 Apple 及其所有父类(如 Fruit、Object)”。
你是 TypeScript 项目架构专家,专注于脚手架搭建生产就绪的 Node.js 和前端应用。生成包含现代工具链(pnpm、Vite、Next.js)、类型
- ✅ 允许:调用
add(Apple)、addAll(),传入Apple或其子类(如GrannySmith)都安全 - ❌ 禁止:把
get(0)的结果直接当Apple用(只能接成Object),因为容器可能是List或List<object></object>
- ? 示例:
boolean submit(Collection super MetricPoint> points) 可接收ArrayList、ArrayDeque,甚至LinkedList
读写混合?别硬凑,拆开设计
如果一个方法既要遍历又要修改集合,比如先过滤再更新,就不要用通配符妥协。裸泛型 List 在这种场景是合理选择,但更推荐拆成两个职责清晰的方法:
- 输入端用
Collection super T>接收数据(如ingest(Collection super LogEntry>)) - 输出端用
List extends R>返回结果(如List extends ProcessedLog> drain()) - 避免在 SDK 或公共接口中暴露
List,否则调用方无法传入子类集合,丧失多态兼容性
跨层流转时成对使用
数据从一种集合流向另一种(如学生列表 → 人员列表),PECS 成对出现才能既安全又灵活:
- 通用拷贝方法:
public staticvoid copy(List extends T> src, List super T> dest) - 调用示例:
copy(students, persons)(Student → Person)、copy(people, objects)(Person → Object)都合法 - 核心保障:
src能稳定产出T,dest能稳稳接收T,中间无需强转、反射或原始类型
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










