iterator 是典型的生产者,因其仅通过 next() 向外产出元素且无写入方法,故适用 pecs 的 “producer extends” 原则,应使用 iterator

Java 中 Iterator 的读取行为天然契合 PECS 原则里的 Producer Extends,即协变设计。
为什么 Iterator 是典型的生产者(Producer)
Iterator<e></e> 的核心职责是向外提供元素——只暴露 next() 和 hasNext(),不接收外部数据写入。它不修改被遍历的集合,也不接受新元素注入,纯粹“产出”已存在的元素。这种单向输出语义,正是 PECS 中 “Producer” 的定义。
- 调用
next()得到一个E类型实例 → 向外“生产”类型为E的对象 - 没有类似
add(E)或set(E)的写方法(remove()操作的是原集合,不是向迭代器写入) - 因此,当泛型参数用于“只读产出”场景时,应倾向使用上界通配符
? extends E
协变体现在泛型通配符的实际应用中
假设你有一个方法,只需遍历任意水果子类的集合(如 List<apple></apple> 或 List<banana></banana>),并统一按 Fruit 处理:
- 正确写法:
void processFruits(Iterator extends Fruit> iter) - 这样能安全接收
new ArrayList<apple>().iterator()</apple>或new ArrayList<banana>().iterator()</banana> - 每次调用
iter.next()返回的是Fruit或其子类实例,可直接赋值给Fruit变量,无需强转 - 而
Iterator<fruit></fruit>无法接收Apple迭代器,因为泛型类型不具备继承关系(非协变)
与集合本身协变性的区别
注意:Iterator 接口自身并未声明为协变(Java 不支持泛型接口的声明时协变,如 interface Iterator),但它的使用方式通过 ? extends 实现了逻辑上的协变效果:
- 数组是天然协变的:
String[]可赋给Object[] - 泛型集合默认不变:
List<string></string>≠List<object></object> - 而
Iterator extends Object>可接收任何Iterator<t></t>(只要T是Object子类),这就是 PECS 在读取端补足协变能力的关键机制
对比 Consumer 场景更能看清差异
如果换成写入操作(比如自定义批量填充方法),就需要 ? super:
-
void fill(Iterator super Apple> iter, List<apple> apples)</apple>—— 表示这个迭代器能接收Apple或其父类(如Fruit、Object) - 但标准
Iterator接口没有写入方法,所以它本身不适用super;只有像Collection.add()这类消费者行为才用? super - 这也反向印证:Iterator 就是为读而生,PECS 在这里只走
extends这一条路
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











