通配符因类型安全牺牲读写灵活性:无界通配符list可读object、仅写null;上界

因为通配符的设计本质是**牺牲写入或读取的灵活性,来换取类型安全**。当既要读又要写时,通配符无法同时满足两者的类型约束,编译器会直接拒绝。
无界通配符 List>:读可以,写只允许 null
声明为 List> 的引用,表示“某个具体但未知的类型”的集合。编译器只知道元素类型一致,但完全不确定是 String、Integer 还是其他类。
- 读取时,所有元素统一视为
Object,安全 —— 因为任何对象都是 Object 的实例 - 写入时,除了
null,编译器不敢让你加任何具体值:加"abc"可能破坏List<integer></integer>的一致性;加42又可能破坏List<string></string>的一致性
上界通配符 List extends T>:可读 T 及其子类,不可写(除 null)
例如 List extends Number> 可能指向 List<integer></integer>、List<double></double> 或 List<number></number>。
Java JDK 25 来自 OpenJDK 官方归档,版本为 JDK 25,本条下载地址已指向官方 Windows x64 zip 安装包直链,适合调试旧项目或兼容旧版 Java 运行环境。
- 读取安全:无论实际是什么子类,都能赋值给
Number引用 - 写入不安全:你无法确定该集合是否接受
Integer(万一它是List<double></double>?),也无法确定是否接受Double(万一它是List<integer></integer>?)—— 所以一律禁止添加
下界通配符 List super T>:可写 T 及其子类,但读只能得 Object
例如 List super Integer> 可能指向 List<integer></integer>、List<number></number> 或 List<object></object>。
- 写入安全:
Integer及其子类(如Long不行,但AtomicInteger可以)一定能放进这三者中的任一个 - 读取不安全:取出来的可能是
Integer,也可能是Number实例,甚至Object实例(比如你之前 add 过一个new Object()),编译器唯一能保证的只有Object
根本矛盾在于:读和写的类型方向相反
读操作要求“向上兼容”(子类 → 父类),写操作要求“向下兼容”(父类 ← 子类)。通配符一次只能锚定一个方向:
-
? extends T锚定读的上限,放弃写的确定性 -
? super T锚定写的下限,放弃读的确定性 -
?两者都放弃,只剩Object和null
所以,真要既读又写,就该用具体类型(如 List<string></string>)或泛型方法参数(如 <t> void process(List<t> list)</t></t>),而不是通配符。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










