上限通配符通过 ? extends T 限定类型为 T 或其子类/实现类,编译期强制类型安全,适用于只读场景,允许安全读取上界类型数据,但禁止添加非 null 元素。

Java 上限通配符通过 ? extends T 语法限定类型,表示“该位置接受的类型必须是 T 或 T 的任意子类(或实现 T 接口的类)”。
限定逻辑与关键规则
上限通配符不是在运行时检查,而是在编译期强制类型安全。它不关心具体是哪个子类,只确保所有可能的类型都“属于 T 家族”。
-
T 可以是类或接口:例如
? extends Number、? extends Comparable<String>、? extends Runnable -
extends 在此处不单指继承:对接口也适用,语义等价于“是 T 的子类型”,涵盖
class A extends B和class C implements D两种情况 -
不能用于泛型类声明的类型参数本身:比如
class Box<? extends Number>是非法的;但可用于变量、方法参数、返回值等使用位置
典型使用场景
主要用在“只读”(生产者)场景,即你需要从容器中安全地取出数据,且能统一按父类型处理。
- 方法参数接收多种子类型集合:
void process(List<? extends Number> nums)可传入List<Integer>、List<BigDecimal>等 - 声明只读引用:
Collection<? extends CharSequence> texts = new ArrayList<String>(); - 配合泛型方法提升复用性,避免为每个子类写重载
不能做什么?——常见限制
上限通配符的核心代价是写入受限,这是类型安全的必然取舍。
立即学习“Java免费学习笔记(深入)”;
-
不能向其中添加任何具体元素(
null除外):编译器无法确认你加的Integer是否会破坏一个实际是List<Double>的引用 -
不能调用需要具体泛型类型的方法:例如
list.set(0, someValue)会报错,因为someValue类型无法匹配未知子类型 -
不能用作泛型类的类型实参构造对象:如
new ArrayList<? extends Number>()编译不通过(需明确具体类型)
正确示例对比
以下代码体现限定生效:
List<? extends Number> safeList = new ArrayList<Integer>(); // ✅ 允许 safeList = new ArrayList<AtomicInteger>(); // ✅ AtomicInteger 是 Number 子类 safeList = new ArrayList<String>(); // ❌ 编译错误:String 不是 Number 子类 Number n = safeList.get(0); // ✅ 安全读取,返回上界类型 // safeList.add(42); // ❌ 编译错误 safeList.add(null); // ✅ 唯一允许的写入


















