pecs原则是策略模式中泛型抽象类类型安全的必要约束:只读用? extends t,只写用? super t,读写兼有则用具体泛型t,返回值方向相反但逻辑一致。

在策略模式中使用泛型抽象类时,PECS 原则不是可选项,而是类型安全的必要约束——它直接决定方法能否被子类正确实现、参数能否被安全传入、返回值能否被安全使用。
策略方法只读输入(生产者场景)用 ? extends T
当抽象策略方法仅从入参集合中读取数据(如遍历校验、计算聚合),不修改集合本身,该集合就是“生产者”。此时应声明为 List extends T>。
- 编译器保证:所有元素可安全向上转型为 T,例如
Fruit f = list.get(0)合法 - 禁止写入:
list.add(...)编译失败,避免向List<apple></apple>中误加Banana - 典型用法:
abstract void validate(List extends Order> orders),允许传入List<onlineorder></onlineorder>或List<storeorder></storeorder>
策略方法只写输出(消费者场景)用 ? super T
当抽象策略方法负责向集合中添加结果(如收集日志、缓存中间值),该集合就是“消费者”。此时应声明为 List super T>。
- 编译器保证:
list.add(new T())安全,因为实际类型至少是 T 的父类(如List<object></object>或List<event></event>) - 读取受限:只能声明为
Object o = list.get(0),无法直接转为 T —— 这正是设计意图:你只负责“放”,不负责“取” - 典型用法:
abstract void collectErrors(List super ValidationError> errors),可接收List<validationerror></validationerror>或更宽泛的List<throwable></throwable>
策略方法需同时读写时,放弃通配符,用具体泛型
如果某个策略方法既要从集合读,又要往里写(例如就地修正数据),说明它承担双重角色,PECS 不适用。此时必须使用确定类型:
- 声明为
List<t></t>,而非通配符 —— 类型完全对齐,读写都安全 - 子类实现时,泛型实参必须严格匹配,例如
class DiscountStrategy extends Strategy<product></product> - 强行用
? extends T或? super T会导致一半操作被禁用,违背策略封装初衷
返回值类型遵循相同逻辑,但方向相反
返回值代表策略向外“产出”的数据,本质是调用方的“生产者”:
- 若返回一个只供外部读取的集合(如查询结果),用
List extends Result>—— 调用方可安全遍历,但不能往里塞东西 - 若返回一个供外部写入的容器(如回调缓冲区),用
List super Input>—— 调用方可安全添加Input子类,但读取只能得Object - 返回单个对象(如
T compute())无需通配符,直接用T即可
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











