PECS规则是“Producer Extends, Consumer Super”的缩写,指导泛型通配符选用:只读(生产者)用? extends T,只写(消费者)用? super T,既读又写则用精确类型T。

什么是 PECS 规则
PECS 是“Producer Extends, Consumer Super”的缩写,出自《Effective Java》。它指导我们如何在使用泛型通配符 ? extends T 和 ? super T 时选择正确的边界:
-
如果泛型参数只用来“产出”(读取)数据 → 用
? extends T:比如从集合中 get 元素,返回值是 T 的子类型,安全。 -
如果泛型参数只用来“消费”(写入)数据 → 用
? super T:比如向集合中 add 元素,能接受 T 及其父类型,保证类型兼容。
违反 PECS 容易导致编译错误或运行时类型不安全,尤其在设计通用工具方法时必须明确角色。
拷贝方法的输入与输出角色要分开看
一个通用数据拷贝方法(如把 List 拷贝到 List),本质是:从源集合“读取”A 类型对象,向目标集合“写入”B 类型对象。二者角色不同,通配符不能混用:
- 源集合是 Producer of A → 应声明为
List extends A>(允许传入List<a></a>、List<suba></suba>等)。 - 目标集合是 Consumer of B → 应声明为
List super B>(允许传入List<b></b>、List<object></object>、List<serializable></serializable>等)。
注意:这里假设存在从 A 到 B 的转换逻辑(如构造函数、静态工厂、Function),否则无法完成类型转换。
立即学习“Java免费学习笔记(深入)”;
正确签名与实现示例
以下是一个类型安全、符合 PECS 的通用拷贝方法:
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
public static <A, B> void copy(List<? extends A> source,
List<? super B> target,
Function<A, B> converter) {
for (A item : source) {
target.add(converter.apply(item));
}
}
调用示例:
-
copy(strings, objects, s -> (Object) s);(strings: List<String>,objects: List<Object>)✅ -
copy(integers, numbers, i -> (Number) i);(integers: List<Integer>,numbers: List<Number>)✅ -
copy(listOfAnimal, listOfObject, a -> a);(List<? extends Animal>→List<? super Object>)✅
这个签名既宽松(支持子类/父类集合),又安全(编译器阻止非法读写)。
常见错误及为什么错
❌ 错误 1:统一用 ? extends Object 或 ? super Object
-
List<? extends Object>看似“万能”,但你 不能往里 add 任何东西(除了 null),因为编译器不知道具体上界。 -
List<? super Object>虽然能 add,但你 无法安全 get 出有意义的类型(只能得到 Object),失去泛型意义。
❌ 错误 2:源和目标都用 ? extends T
- 目标变成只读,add 会编译失败 —— 忘了它是 consumer。
❌ 错误 3:忽略转换函数的类型约束
- 若 converter 返回类型不是 B,或参数类型不能接收 A 的子类,则类型推导失败或运行异常。
核心原则:谁读谁写,各守边界,不越位。

















