collections.copy(dest, src) 是 pecs 原则的典范实现:src 为只读生产者(list

Java 中 Collections.copy(dest, src) 是 PECS 原则最干净、最锋利的一次落地——没有冗余,没有妥协,通配符用得恰到好处,每一处设计都服务于“安全搬运”这一个目标。
参数类型就是角色宣言
方法签名直白宣告了两个集合的职责:
-
List extends T> src:只读生产者。它产出T或其子类实例,get()返回值可直接当T用,但禁止add()(连null都不行) -
List super T> dest:只写消费者。它能接收T及所有子类对象,set()或add()安全,但get()只能返回Object(类型信息被擦除)
这不是泛型炫技,而是把“谁负责出、谁负责进”刻进方法契约里。
编译器全程盯梢,不靠运行时补救
PECS 的威力在于编译期拦截非法组合:
- ✅
copy(new ArrayList<person>(), new ArrayList<student>())</student></person>:Student 是 Person 子类 →src能产,dest能收 - ✅
copy(new ArrayList<object>(), new ArrayList<string>())</string></object>:String → Object,合法 - ❌
copy(new ArrayList<string>(), new ArrayList<object>())</object></string>:Object 不是 String 子类 →src无法保证只产 String,编译失败
错误在写代码时就被挡住,而不是等到 ClassCastException 在深夜报警。
底层循环极度克制,只做一件事
源码逻辑就一行实质操作:
dest.set(i, src.get(i));
而它的安全,完全依赖两个通配符的配合:
-
src.get(i)返回T(由? extends T保证) -
dest.set(i, ...)接收T(由? super T保证)
没有转型,没有判空,没有兜底逻辑——因为类型系统已经把路铺平了。
不支持自动扩容,恰恰是 PECS 的清醒
很多人抱怨 Collections.copy() 要求 dest.size() >= src.size(),甚至抛 IndexOutOfBoundsException。但这不是缺陷,是原则的延伸:
- 它只管“搬”,不管“建容器”——职责单一
- 如果允许动态扩容,就得在内部调用
add(),而? super T的add()虽安全,却可能破坏目标列表原有结构(比如Arrays.asList()返回的不可变列表) - 强制显式准备容量,反而让调用方清楚意识到:这是覆盖式写入,不是追加
这种“不友好”,其实是对语义完整性的坚持。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











