上限通配符 ? extends T 限制泛型为 T 或其子类,确保类型安全但禁止添加非 null 元素,适用于只读“生产者”场景,与类型参数限定 的可命名、可复用语义不同。

上限通配符 ? extends T 的作用是把泛型参数限制为 T 类型本身,或其任意子类(包括直接子类和间接子类)。它不表示“继承关系”的动作,而是一种类型兼容性约束,确保传入的泛型实参不会超出 T 所定义的安全边界。
核心限制逻辑
编译器只允许你使用满足以下条件的类型来替代 ? extends T:
- 必须是 T 的具体子类型(如
Integer、Double),或 - 就是 T 本身(如
Number),或 - 实现了 T 接口的类(当 T 是接口时,例如
? extends Comparable)
一旦声明为 List extends Number>,你就不能再往这个集合里添加任何元素(除 null 外),因为编译器无法确认具体类型——可能是 Integer,也可能是 BigDecimal,写入 new Integer(1) 对前者合法,对后者却可能出错。
典型使用场景
它适用于只读操作为主的场合,也就是“生产者”角色(Producer)。常见例子包括:
- 方法接收多种 Number 子类型的集合统一处理:
void printAll(Collection extends Number> nums) - 从泛型容器中安全获取值并向上转型:
Number n = box.get();(其中box是Box extends Number>) - 泛型方法返回更宽泛但类型安全的结果:
publicList getNumbers() { ... }
不能做的事(关键限制)
这些操作在编译期就会被拒绝,是上限通配符强制执行的安全机制:
- 向集合中添加任何非
null元素(list.add(1)报错) - 将
? extends T直接用作泛型类的类型参数定义(如class A extends Number>是非法语法) - 在 new 表达式中直接实例化带通配符的泛型类型(
new ArrayList extends Number>()不合法)
和类型参数限定 的区别
虽然都用 extends,但语义不同:
-
出现在类/方法声明中,定义的是一个可命名、可复用的类型变量,后续可在方法体里自由读写 -
? extends Number是匿名通配符,用于变量、参数、返回值等位置,强调“兼容多个子类型”,但放弃写入能力以换取类型安全











