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

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











