Java中泛型通配符通过? extends T(上界)支持安全读取、? super T(下界)支持安全写入,分别实现“读取多态”与“写入多态”,遵循PECS原则;二者不可混用于同一读写场景,因类型未知导致编译器无法同时保障读写安全。

Java 中泛型通配符本身不直接体现“多态”行为,但它的上下界设计正是为了在类型安全前提下模拟多态的灵活性——比如让一个方法既能处理 Integer,也能处理 Double,只要它们都属于 Number 体系。这种能力依赖于 ? extends T(上界)和 ? super T(下界)的约束机制,本质是编译器利用继承/实现关系做静态推断。
上界通配符 ? extends T:支持“读取多态”
它表示“某个未知类型,但一定是 T 或其子类”。编译器据此知道:从集合中取出的元素,至少具备 T 类型的方法。
-
能做什么:调用
T声明的所有方法,例如List extends Number>可以安全调用get(0).doubleValue() -
不能做什么:除
null外,禁止add()——因为实际类型可能是Integer、Double或其他子类,编译器无法确认你添加的实例是否兼容 - 典型场景:作为生产者(Producer),比如遍历、计算、格式化数值列表
下界通配符 ? super T:支持“写入多态”
它表示“某个未知类型,但一定是 T 或其父类”。编译器据此知道:任何 T 类型或其子类的实例,都能安全放入该容器。
-
能做什么:向集合中添加
T或其子类对象,例如List super Integer>可以add(new Integer(1))、add(new Long(2))(如果Long是Integer的子类?注意:实际不是,但Integer本身可加) -
不能做什么:取出的元素只能当作
Object使用,因为下界太宽,编译器无法确定具体返回类型 - 典型场景:作为消费者(Consumer),比如收集数据、批量插入、归并操作
为什么不能同时读又写?
通配符类型变量(如 List extends Number>)的类型在声明时就是“未知且固定”的。编译器既不知道它具体是 ArrayList 还是 ArrayList,也无法反向推导出统一的可写类型。所以:
- 想安全读 → 用
? extends T - 想安全写 → 用
? super T - 既要读又要写 → 直接用具体类型参数
T,例如void process(List list)
多重上界与接口实现的多态延伸
当泛型类型参数用 T extends A & B & C 限定时,T 必须同时是类 A 的子类,并实现接口 B 和 C。这相当于要求类型具备多个契约,是面向接口编程中“多实现多态”的泛型表达。
- 类必须放在第一位,且只能有一个;接口可多个,用
&连接 - 方法体内可放心调用
A、B、C中定义的所有公共方法 - 例如:
表示该类型既是数值、可比较、又可序列化& Serializable>
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











