Java上下界通配符不是语法糖,而是将继承关系与职责边界显式编码进类型系统:? extends体现只读契约,支持里氏替换;? super体现写入兼容,支持向上转型;PECS原则使泛型签名成为可读的设计文档。

Java 中上下界通配符不是语法糖,而是面向对象设计在泛型层面的自然延伸——它把“继承关系”和“职责边界”显式编码进类型系统里。配合得当,能清晰表达类与方法的设计意图:谁负责提供数据,谁负责接收数据,谁只做通用协调。
用 ? extends 体现“只读契约”,强化里氏替换
当一个方法声明参数为 List<? extends Number>,本质上是在说:“我只消费 Number 及其子类的实例,且绝不破坏你原有类型的完整性”。这直接呼应里氏替换原则(Liskov Substitution Principle):任何 List<Integer> 或 List<Double> 都可安全传入,因为它们的行为不会超出 Number 所承诺的能力范围。
- 调用
get()返回Number,可直接用于数值计算、格式化等通用逻辑 - 禁止
add()不是限制,而是保护——避免向List<Integer>中误加Double导致运行时类型不一致 - 常见于统计工具、序列化器、只读视图(如
asUnmodifiableList()的入参)
用 ? super 体现“写入兼容”,支持向上抽象
List<? super Integer> 表达的是“我接受一切能装下 Integer 的容器”,这背后是面向对象中“向上转型”的安全应用。父类容器(如 List<Number>、List<Object>)天然比子类容器更宽泛,而 ? super 让这种宽泛性在编译期就可验证。
- 允许
add(new Integer(42)),因为Integer是所有这些上界类型的合法子实例 - 读取时只能用
Object接收,这是有意为之的约束——你不该依赖具体类型,因为调用方本就可以传List<Object> - 典型场景:集合填充工具(如
Collections.addAll())、事件总线投递、批量入库适配器
按职责分离组织 API,让泛型成为设计文档
把 PECS 原则落实到接口设计中,泛型签名本身就变成可读的设计说明:
立即学习“Java免费学习笔记(深入)”;
- 接口方法返回
Collection<? extends Product>→ “我产出产品,你按需处理,别指望我能让你往里塞东西” - 服务方法参数是
Consumer<? super OrderEvent>→ “我推送订单事件,你注册的监听器必须能处理 OrderEvent 及其所有父类事件(如 Event)” - 工具类方法用
<T> void copy(List<? extends T> src, List<? super T> dst)→ 清晰定义了数据流向:src 是生产者,dst 是消费者
这种写法不增加运行时开销,却极大降低了使用者的理解成本和误用风险——类型系统成了最严格的架构审查员。


















