pecs原则核心是按操作意图选通配符:只读用? extends t,只写用? super t;生产者(向外提供数据)用extends确保安全产出,消费者(向内接收数据)用super确保宽泛容纳。

PECS 原则的核心定义,一句话就能说清:**谁往外“给”数据,就用 ? extends T;谁往里“收”数据,就用 ? super T。** 它不是语法规定,而是类型安全下的自然选择——围绕“读”和“写”的方向,决定通配符该用上界还是下界。
Producer Extends:只读场景,安全地向上转型
当一个泛型容器只被用来“取出”元素(比如遍历、计算、打印),它就是生产者。此时用 ? extends T,表示里面装的是 T 或它的任意子类。
- ✅ 读取安全:所有元素都能当作
T使用(例如List extends Number>中的元素可直接赋值给Number变量) - ❌ 写入禁止:不能 add 任何具体类型(包括
T),因为编译器无法确认实际集合类型(可能是ArrayList<integer></integer>,也可能是ArrayList<double></double>) - ⚠️ 唯一例外:可以 add
null(它是所有引用类型的合法值)
Consumer Super:只写场景,安全地向下兼容
当一个泛型容器只被用来“塞入”元素(比如批量添加、归并、填充),它就是消费者。此时用 ? super T,表示它能接受 T 或它的任意父类。
Java JDK 25 来自 OpenJDK 官方归档,版本为 JDK 25,本条下载地址已指向官方 Windows x64 zip 安装包直链,适合调试旧项目或兼容旧版 Java 运行环境。
- ✅ 写入安全:可以 add 所有
T类型及其子类对象(例如List super Integer>能 addInteger、Long等,只要它们是Integer的子类或本身) - ❌ 读取受限:get 出来的元素只能当作
Object处理(因为真实类型可能是Number、Object等更宽泛的类型) - ? 典型用途:像
Collection.addAll()、Stream.collect()这类接收数据的方法参数,都采用? super T
为什么不是“既能读又能写”?
Java 泛型是不变的(invariant)。List<string></string> 和 List<object></object> 没有父子关系。PECS 不是在绕过这个限制,而是在承认限制的前提下,为不同使用意图分别提供最宽松又最安全的类型表达:
- 想读?那就放宽“来源”范围 → 上界
extends - 想写?那就放宽“目标”范围 → 下界
super - 既想读又想写?那就别用通配符,直接用具体类型(如
List<t></t>)
记法小技巧
不用死记缩写,抓住动词:
- Extends → “extends from T”:元素“从 T 延伸出来”,所以是子类,适合往外给(Producer)
- Super → “accepts super of T”:容器“能接受 T 的上级”,所以是父类,适合往里收(Consumer)
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










