泛型通配符用于解决类型兼容与类型安全的平衡,? extends T 适用于只读场景,? super T 适用于只写场景,PECS原则指导数据搬运,? 仅支持不依赖元素类型的通用操作。

泛型通配符在集合中的实战,核心是解决“类型兼容但又不能破坏类型安全”的问题。它不用于定义类或创建实例,而是在方法参数、返回值或局部变量中,让集合能接受更宽泛的类型范围,同时明确约束读写行为。
什么时候必须用 ? extends T(上界通配符)
当你只从集合里取数据,且希望它能处理 T 及其所有子类时,就用 ? extends T。
- 典型场景:计算数字总和、查找最大值、遍历打印等只读操作
- 编译器保证:get() 返回的是 T 类型(或其子类),可直接当 T 用
- 禁止操作:add() 任何非 null 值都会报错——因为实际类型可能是 Dog、Cat 或 Animal,编译器无法确认你加的是否合法
- 例子:sum(List extends Number> numbers) 可接收
List、List、List,但不能往里面 add(1)
什么时候必须用 ? super T(下界通配符)
当你只往集合里放数据,且希望它能接收 T 及其所有父类时,就用 ? super T。
- 典型场景:批量添加元素、收集结果、归并数据等只写操作
- 编译器保证:add(T) 安全——T 可以向上转型为任意父类(比如 Integer → Number → Object)
- 限制读取:get() 返回的是 Object,若要当 T 用,必须强转(通常不推荐)
- 例子:collectIntegers(List super Integer> target) 可接收
List、List、List,能安全 add(new Integer(42))
怎么组合使用实现数据搬运(PECS 经典实践)
一个常见需求是把源集合的元素复制到目标集合。这时要分开看角色:源是生产者(Producer),目标是消费者(Consumer)。
- 源集合用
? extends T:确保能安全读出 T 类型元素 - 目标集合用
? super T:确保能安全写入 T 类型元素 - 代码示例:
public static
for (T item : src) {
dest.add(item); // 编译通过,类型安全
}
}
调用时:copy(listOfDogs, listOfAnimals) 或 copy(listOfInts, listOfNumbers) 都合法。
无界通配符 ? 的实用定位
? 表示完全未知类型,它不是万能占位符,而是“只做通用操作”的信号。
- 适用操作:size()、isEmpty()、clear()、contains()、iterator() 等不依赖元素具体类型的方法
- 不适用操作:add()(除 null)、get() 后直接调用元素方法(因类型未知,只能当 Object 用)
- 典型用途:工具方法签名,如 printSize(Collection> c),或泛型容器的桥接封装
- 注意:不要用
List>接收new ArrayList后再试图 add("x")——会编译失败()











