上界通配符 ? extends number 禁止写入(null 除外)以保障类型安全,因编译器无法确定具体子类型;get() 返回 number 类型可安全读取;需写入时应改用 list 或 ? super number。

因为上界通配符 ? extends Number 表示“某个未知的、继承自 Number 的具体类型”,编译器无法确定该集合实际容纳的是 Integer、Double 还是其他子类,为保障类型安全,禁止向其中写入任何具体值(null 除外)。
上界通配符的本质是“只读语义”
声明如 List extends Number> 时,Java 泛型系统只知道它内部元素是某个确定但未知的 Number 子类型(比如可能是 List<integer></integer>,也可能是 List<bigdecimal></bigdecimal>),但编译器无法在编译期确认到底是哪一个。
- 如果允许调用
add(new Integer(1)),而实际引用的是List<double></double>,就会破坏类型安全; - 同理,
add(new Double(2.0))对List<integer></integer>同样非法; - 唯一能保证安全的写入值是
null——因为null可赋给任意引用类型,不违背任何具体子类型的约束。
为什么 get() 却可以安全读取
从 ? extends Number 中读取元素时,返回类型被统一上界推断为 Number:
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
- 无论底层是
Integer、Float还是BigInteger,它们都 IS-ANumber; - 所以
list.get(0)的返回类型是Number,可安全赋值给Number或其父类(如Object)变量。
想写入怎么办?用下界通配符或具体类型
若需向集合添加元素,应避免使用上界通配符,改用:
-
具体泛型类型:如
List<number></number>—— 可 add 任意Number子类实例; -
下界通配符
? super Number:表示“某个Number的父类或自身”,此时可 add 所有Number子类(PECS 原则中的 “Consumer” 场景); - 原始类型或无泛型操作(不推荐,丢失类型安全)。
一个典型反例说明问题
假设你有:
List extends Number> list = new ArrayList<integer>(); list.add(new Double(3.14)); // 编译错误! </integer>
这行代码看似只是往“数字列表”加个数字,但实际会把 Double 插入到本应只存 Integer 的容器中,JVM 无法在运行时检查(泛型已擦除),所以编译器提前拦截。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










