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),否则无法完成类型转换。
正确签名与实现示例
以下是一个类型安全、符合 PECS 的通用拷贝方法:
public static <a b> void copy(List extends A> source,
List super B> target,
Function</a><a b> converter) {
for (A item : source) {
target.add(converter.apply(item));
}
}</a>
调用示例:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
-
copy(strings, objects, s -> (Object) s);(strings: List<string></string>,objects: List<object></object>)✅ -
copy(integers, numbers, i -> (Number) i);(integers: List<integer></integer>,numbers: List<number></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 的子类,则类型推导失败或运行异常。
核心原则:谁读谁写,各守边界,不越位。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










