? extends t 用于安全读取多种子类型数据并禁止不安全写入,只允许以t类型读取(如number),add()等写入操作被禁止(null除外)。

用 ? extends T 是为了安全读取多种子类型的数据,同时禁止不安全的写入操作。它不是在描述“容器里装的是什么”,而是在声明“你能从里面安全拿到什么”——只能以 T 类型读取,不能往里加(null 除外)。
什么时候该用 ? extends T
当你需要一个方法能接收 不同子类型集合但只读取数据 时,就适合用上限通配符。比如处理数值类型:
-
List<integer></integer>、List<double></double>、List<bigdecimal></bigdecimal>都是Number的子类,但它们彼此没有继承关系 - 不用
? extends Number,就得为每种类型单独写重载方法 - 加上后,一个方法就能统一处理所有
Number子类的集合
它能做什么、不能做什么
编译器只知道元素是 “某个未知的 T 子类”,所以:
- ✅
get(i)返回类型是T(如Number),可直接调用T定义的方法,比如doubleValue() - ❌
add()、set()全部编译报错,哪怕传入new Integer(1)或new Number()(抽象类无法实例化)也不行 - ⚠️
add(null)是唯一允许的写入操作,但通常没实际意义
典型写法和常见误区
正确用法示例:
public static void printNumbers(Collection extends Number> data) {
for (Number n : data) {
System.out.println(n.doubleValue()); // 安全调用
}
}
调用时可传入 ArrayList<integer></integer>、Set<float></float>、LinkedList<bigdecimal></bigdecimal> 等任意 Number 子类型集合。
容易踩坑的地方:
- 不能把
get(0)强转成具体子类,比如(Integer) list.get(0),除非先做instanceof检查 - 不能用作方法返回值类型,如
List extends Number> getNumbers(),否则调用方无法安全添加元素 - 不能出现在类或接口的类型参数定义中,例如
class Container extends Number>是非法语法
配合泛型方法提升灵活性
单独用 ? extends T 限制写入,但结合泛型方法参数,就能在读取后做进一步处理:
<t extends comparable>> T max(List extends T> list)</t>
这样既支持 List<string></string>,也支持 List<localdate></localdate>,内部仍用 ? extends T 接收保证输入兼容性,返回值却是确定的 T 类型。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











