List<? super Integer>写入只允许Integer及其子类以保障类型安全,读取只能返回Object因上界不确定;其设计定位为“消费者”,牺牲读取精度换取写入灵活性与安全性。

因为 List<? super Integer> 表示“某个未知类型,但它至少是 Integer 的父类(比如 Number 或 Object)”,编译器只知道下界,不知道上界——写入时靠下界保障安全,读取时因上界不确定,只能退到最宽泛的 Object。
写入为什么只允许 Integer 及其子类
编译器在类型检查阶段确认:只要往集合里加的是 Integer 或它的子类(比如自定义的 MyInt extends Integer),就一定能被所有可能的实际类型容纳:
-
List<Integer>当然能存Integer -
List<Number>能存Integer(因为Integer是Number子类) -
List<Object>更能存Integer(一切对象都是Object)
但加 Double 就不行——如果实际引用的是 List<Integer>,那就会破坏类型约束;编译器禁止这种风险操作。
读取为什么只能是 Object
你无法预知这个通配符实际指向哪个具体类型:
立即学习“Java免费学习笔记(深入)”;
- 它可能是
List<Integer>→get(0)返回Integer - 也可能是
List<Number>→get(0)返回Double或Integer - 还可能是
List<Object>→get(0)返回String、Thread等任意对象
唯一所有情况都成立的公共类型只有 Object。编译器不猜、不假设,直接限定返回类型为 Object,避免强制转型时的 ClassCastException。
这不是缺陷,而是类型安全的设计取舍
? super T 的定位就是“消费者”——专为写入服务。它用牺牲读取的精确性,换来了写入的灵活性和安全性:
- 你可以把一个方法设计成接收
List<? super Integer>,让它既能处理ArrayList<Integer>,也能处理LinkedList<Number>,甚至CopyOnWriteArrayList<Object> - 但一旦需要读取并按具体类型使用元素,就该换用
? extends T或明确的具体泛型类型
泛型擦除后运行时确实只剩原始类型,但这一切的安全边界,全由编译期的这套推理机制守住。


















