上限通配符 ? extends T 的核心作用是放宽读取能力、收紧写入权限——它允许安全接收任意 T 的子类型集合,但只允许以 T 类型读取元素,禁止添加(除 null 外)。

上限通配符 ? extends T 的核心作用是**放宽读取能力、收紧写入权限**——它让方法或变量能安全接收任意 T 的子类型集合,但只允许以 T 类型读取元素,禁止添加(除 null 外)。
为什么只能读、不能写
编译器只知道容器里装的是“某个未知的 T 子类”,比如 List<? extends Number> 可能是 List<Integer>,也可能是 List<Double>。若允许 add(new Integer(1)),而实际容器是 Double 列表,就会破坏类型契约。所以编译器直接禁用所有 add、set 等写入操作。
-
get(i)返回类型是T(如Number),可赋值给T或其父类(Object、Serializable) -
add(E)、set(int, E)全部编译报错,哪怕传入T的实例也不行 -
add(null)是唯一被允许的写入操作,但通常无业务意义
典型读取场景与写法
它天然适配“只进不出”的数据处理逻辑,常见于工具方法设计:
- 聚合计算:求和、平均值、最大值等,只要能调用
T定义的方法即可 - 遍历打印:不关心具体子类,只需统一按
T处理 - 只读校验:如检查是否全为正数、是否有序等
示例:
立即学习“Java免费学习笔记(深入)”;
public double sum(List<? extends Number> list) {
return list.stream().mapToDouble(Number::doubleValue).sum();
}
该方法可接受 List<Integer>、List<BigDecimal>、List<Float>,无需重载,且返回值类型明确为 double。
搭配泛型方法提升灵活性
单独用 ? extends T 会限制写入,但结合泛型方法参数,就能在读取后做进一步处理:
- 声明带边界的泛型方法:
<T extends Comparable<T>> T max(List<? extends T> list) - 利用
T推断出具体可比较类型,既支持List<String>也支持List<LocalDate> - 内部仍用
? extends T接收,保证输入兼容性;返回值是确定的T,而非模糊的上界
常见误区提醒
注意几个容易踩坑的点:
- 不能把
get()结果直接强转成某个子类(如(Integer) list.get(0)),除非加instanceof检查 - 不能用作方法返回值类型(如
List<? extends Number> getNumbers()),否则调用方无法安全添加元素 - 不要在类定义中滥用,比如
class Container<? extends Number>是非法语法——通配符只用于使用位置(参数、变量、返回值),不用于类型声明


















