应使用 ? extends t,因为集合作为生产者只输出 t 或其子类实例,需用上界约束确保 get() 元素可安全赋值给 t,但禁止 add() 非 null 值以维护类型安全。

当集合作为数据源(只读、向外提供元素)时,应使用 ? extends T,这是 PECS 中 “Producer Extends” 的直接体现。
为什么必须用 ? extends T
因为集合是“生产者”,它的职责是输出 T 类型或其子类的实例。编译器需要确保从集合中 get() 或遍历时拿到的对象能安全地当作 T 使用——这靠 extends 提供上界约束来保证。
-
List extends Number>可以接收List<integer></integer>、List<double></double>等,所有元素都能赋值给Number变量 - 但不能往里面
add()任何非null值,因为编译器不知道实际类型是Integer还是Double,写入会破坏类型安全
典型使用场景
适用于所有“只取不存”的方法参数或返回类型:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 打印集合内容:
void print(List extends Fruit> fruits) - 计算总和:
double sum(List extends Number> numbers) - 查找最大值:
<t extends comparable super t>> T max(List extends T> list)</t>
常见误用与纠正
容易混淆的是把“能装 T 的子类”等同于“能往里加 T 的子类”。实际上:
- ✅ 正确:
List extends Fruit> src = new ArrayList<apple>(); Fruit f = src.get(0);</apple> - ❌ 错误:
src.add(new Apple());—— 编译失败,类型不确定 - ⚠️ 注意:
src.add(null);是唯一允许的写操作
对比 ? super T 更容易理解
如果这个集合还要接收外部数据(比如往里塞苹果),那它就不是纯生产者,而是消费者,此时该用 ? super Fruit。但只要逻辑明确“只读”,extends 就是唯一安全且符合语义的选择。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










