外层? extends list

List extends List super String>> 这个嵌套泛型看似复杂,但只要一层层按 PECS 原则拆解,就能清晰理解每一层的读写能力与类型约束。
? 外层:? extends List super String>
表示“某个 List super String> 的子类型”,即:
- 实际类型必须是
List super String>或它的子类(如ArrayList super String>、LinkedList super String>等); - 但注意:
List接口本身是 不可继承的类,所以这里的“子类型”实际指 实现了List的具体类,且其泛型参数满足? super String。
✅ 外层是生产者(Producer) → 只能安全读取元素
-
get(i)返回的是List super String>类型(不是String,也不是Object,而是这个确切的上界类型); - 你不能往外层
List中add(...)任何东西(哪怕是new ArrayList<string>()</string>),因为编译器不知道它底层到底是ArrayList super String>还是CopyOnWriteArrayList super String>,更不知道其具体泛型实参——为保安全,禁止写入。
⚠️ 举例:
List extends List super String>> outer = new ArrayList<arraylist>>(); // outer.add(new LinkedList<object>()); // ❌ 编译失败:外层禁止 add List super String> inner = outer.get(0); // ✅ 合法:拿到一个能存 String 及其父类的列表</object></arraylist>
? 内层:? super String
出现在 List super String> 中,表示该内层列表可接受:
Java JDK 25 来自 OpenJDK 官方归档,版本为 JDK 25,本条下载地址已指向官方 Windows x64 zip 安装包直链,适合调试旧项目或兼容旧版 Java 运行环境。
-
String本身,或它的任意父类(如CharSequence、Object,前提是这些类型在继承链中); - 因为
String是 final 类,没有子类,所以? super String实际覆盖范围就是String及其所有父类(Object是终极父类,总成立)。
✅ 内层是消费者(Consumer) → 可以安全写入 String
-
inner.add("hello")✅ 允许(String能放进List<charsequence></charsequence>、List<object></object>等); -
inner.add(new StringBuilder())❌ 不允许(StringBuilder不是String的父类,也不满足? super String); -
inner.get(0)只能赋给Object(因为你不知道它实际是List<string></string>还是List<object></object>,最宽泛的共同类型是Object)。
? 关键点:? super String 不要求容器“只存 String”,而是要求容器至少能存下 String —— 所以 List<object></object>、List<charsequence></charsequence> 都合法,但 List<stringbuilder></stringbuilder> 不合法(它不能保证能装 String)。
? 组合起来看行为边界
| 操作 | 是否允许 | 原因 |
|---|---|---|
outer.add(...) |
❌ 不允许 | 外层是 ? extends ...,PECS → 生产者,禁止写入 |
outer.get(i) |
✅ 返回 List super String>
|
编译器确保取出的是兼容类型,可安全持有 |
inner.add("abc") |
✅ 允许 |
String 满足 ? super String,所有合法目标都能接收 |
inner.add(new Object()) |
❌ 不允许(除非声明为 List<object></object>) |
? super String 并不意味“可以加任意父类”,而是“容器类型 ≥ String”,但添加时仍需满足该容器的实际泛型约束;编译器只允许传 String(或其子类,但 String 无子类),所以仅 String 安全可加
|
String s = inner.get(0) |
❌ 不允许 |
get(0) 类型是 Object,无法直接转 String;必须显式转型或用 instanceof 判断 |
? 补充说明:inner.get(0) 的返回类型是 ? super String,而通配符下限的 get 结果只能向上兼容到 Object。所以正确写法是:
Object obj = inner.get(0); // ✅ 安全
if (obj instanceof String s) { /* ... */ } // 运行时检查
? 总结核心逻辑
- PECS 是逐层生效的:每层通配符独立判断角色(Producer / Consumer),不跨层“传导”。
-
外层
extends→ 控制“谁可以赋值给它” + “它能否被写入”; -
内层
super→ 控制“它能容纳什么” + “从中读出的最窄公共类型”; - 嵌套不是叠加能力,而是叠加限制:越深的嵌套,可用操作越少,但类型安全性越高。
这种结构常见于工具方法中,比如:
public static void copyStringsToAnySuperList(
List<string> src,
List extends List super String>> destContainers) {
for (List super String> dest : destContainers) {
dest.addAll(src); // ✅ addAll 内部用了 ? super String,完美匹配
}
}</string>
不复杂但容易忽略细节。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










