PECS原则在适配器模式中不用于转换数据,而是安全打通源与目标集合的类型通道:只读源用? extends T确保产出T及子类、禁止add;只写目标用? super T确保容纳T及子类、读取仅限Object;成对使用实现编译期类型安全流转。

PECS 原则在适配器模式中不用于“转换数据”,而是用于安全打通源集合与目标集合之间的类型通道——它让适配器方法能接收更广的输入、写出更稳的结果,同时把类型风险拦在编译期。
适配器方法只读源数据时:用 ? extends T
当适配器从源集合提取数据(比如把 List<Student> 映射为 Person 属性),源集合是“生产者”:
- 声明参数为
List<? extends Person>,就能同时接受List<Student>、List<Teacher>、List<Person> - 可直接调用
src.get(i).getName()、.getId()等 Person 定义的方法,无需强转 - 禁止对 src 调用
add()(除 null),避免破坏原始集合类型一致性
适配器方法只写目标数据时:用 ? super T
当适配器向目标集合填充结果(比如把加工后的对象存入更宽泛的容器),目标集合是“消费者”:
- 声明参数为
Collection<? super Person>,就能写入ArrayList<Person>、LinkedList<Object>、Set<Serializable> - 可安全调用
dest.add(person)或dest.add(new Student())(Student 是 Person 子类) - 从中读取元素只能赋给
Object;若需按 Person 使用,说明设计越界——适配器不该承担读取责任
完整适配流程:上下游各守其界
典型场景:把学生列表适配成通用人员记录,并批量写入日志容器。
立即学习“Java免费学习笔记(深入)”;
- 签名示例:
public static void adaptStudents(List<? extends Student> src, Collection<? super Person> dest) - 调用自由:
adaptStudents(students, persons)、adaptStudents(students, objects)全部通过编译 - 内部逻辑只需遍历 src、构造 Person 实例、调用 dest.add(),全程无 cast、无 instanceof、无包装对象
- 若不用 PECS,就得为每种组合写重载,或退化为
Collection<Object>+ 手动转型,既冗余又易错
注意边界:适配器不是类型转换器
PECS 不改变数据本身,也不做运行时类型检查。它只保证:
- 源端拿出的东西“能当 T 用”(向上兼容)
- 目标端收进去的东西“肯定能装下”(向下兼容)
- 真正需要类型转换(如 Student → JSON 字符串)仍由业务逻辑完成,PECS 只为其提供干净的输入输出管道


















