该类型表示一个列表,其元素是某种未知的List子类型,该子类型只能存放某种未知的Number子类型;可安全读出Number,但不能写入任何元素(除null)。

这种写法 List<? extends List<? extends Number>> 在 Java 中是合法的,但**不能安全地向其中写入任何元素(除了 null)**,而读取时需逐层理解通配符的约束。
怎么读这个类型?
它表示:一个列表,其每个元素都是“某种具体的、未知的 List 子类型”,而该子类型本身又只能存放“某种具体的、未知的 Number 子类型”(比如 Integer、Double 等)。
注意:? extends X 表示“某个未知的 X 的子类”,不是“X 或它的子类”的集合;它代表一个**固定但不可知的具体类型**(PECS 原则中的 “Producer Extends”)。
能读出什么?
你可以安全地读取,但类型会逐步变宽:
立即学习“Java免费学习笔记(深入)”;
Java Maven 项目审查工作流的通用输入处理。当 Java Maven 项目以 ZIP压缩包或 GitLab 仓库 URL 形式提供且需要...时使用。
- 外层
List<? extends List<? extends Number>>→ 调用get(i)得到的是List<? extends Number>(不是ArrayList<Integer>这种具体类型) - 再对这个结果调用
get(j)→ 得到的是Number(因为? extends Number的上界是Number,这是唯一能确定的公共父类型)
所以最终你能安全读出的最精确类型就是 Number,不能再当 Integer 或 Double 直接使用(除非显式转型并承担风险)。
为什么不能往里添加元素?
两层都用了 extends,意味着类型参数都是只读的:
- 不能对外层 list 调用
add(...)—— 因为不知道它实际接受哪种List<? extends Number>(比如可能是ArrayList<Integer>,也可能是LinkedList<Double>,传进去任意一种都不安全) - 也不能对内层 list(即你 get 出来的那个)调用
add(...)—— 因为你只知道它是List<? extends Number>,但不知道它具体允许加什么(Integer?BigDecimal?不确定)
实际读取示例
假设你有:
List<List<Integer>> ints = Arrays.asList(
Arrays.asList(1, 2),
Arrays.asList(3, 4, 5)
);
List<? extends List<? extends Number>> data = ints; // 合法赋值
那么可以这样安全读取:
for (List<? extends Number> inner : data) {
for (Number n : inner) {
System.out.println(n.doubleValue()); // 安全:Number 有 doubleValue()
// System.out.println(n.intValue()); // 也安全,但要注意精度丢失
// Integer i = (Integer) n; // 可能 ClassCastException,不推荐直接强转
}
}
如果需要按具体子类型处理,应在外围明确类型(比如用泛型方法接收原始类型),而不是依赖嵌套上界通配符。

















