? extends t用于只读(生产者),可安全读取为t类型但禁止写入;? super t用于只写(消费者),可安全写入t类型但读取仅得object,遵循pecs原则。

Java 泛型中,? extends T 和 ? super T 是两种带边界的通配符,用来在不确定具体类型时,安全地放宽或收紧泛型参数的取值范围。它们不改变泛型本身的不变性,而是通过编译器静态推断,在“读”和“写”两个方向上分别提供类型安全的灵活性。
? extends T:用于安全读取,限定上界
表示“某个未知类型,但一定是 T 或其子类”。编译器知道从该结构中取出的每个元素,至少具备 T 类型的方法。
- 能调用 T 声明的所有方法,比如
List extends Number>中的元素可直接调用doubleValue() - 不能向其中添加任何非 null 元素——因为实际类型可能是 Integer、Double 或其他子类,编译器无法验证你 add 的对象是否兼容
- 典型用途是作为“生产者”(Producer),如遍历、求和、格式化等只读操作
- 例如:
public static double sum(List extends Number> list)可接收List<integer></integer>、List<double></double>等
? super T:用于安全写入,限定下界
表示“某个未知类型,但一定是 T 或其父类”。编译器知道任何 T 类型或其子类的实例,都能放进这个结构里。
- 可以向其中添加 T 或其子类的对象,比如
List super Integer>能 addnew Integer(1)、new Long(2)(如果 Long 是 Integer 子类?注意:实际不是;但 Integer 本身可加) - 从中读出的元素只能当作
Object使用——因为下界太宽,编译器无法确定具体返回类型 - 典型用途是作为“消费者”(Consumer),如集合批量添加、归并等写入操作
- 例如:
Collections.<integer>addAll(List super Integer>, Integer...)</integer>就是标准库中典型的下界应用
为什么不能混用?PECS 原则是关键
PECS(Producer Extends, Consumer Super)提醒我们:一个泛型位置通常只承担一种角色——要么产出数据,要么消费数据。
- 同一变量或形参若既想读又想写,用通配符会失败:? extends T 不让写,? super T 不让读,两者逻辑冲突
- 需要读写兼顾时,应使用具体类型参数(如
<t extends number></t>)或无界通配符?(仅限调用 Object 方法) - 边界选择本质是权衡:上界换来读的安全与灵活,下界换来写的兼容与开放
边界语法小贴士
注意几个易错点:
-
extends在泛型边界中泛指“继承或实现”,可用于类或接口,支持多边界,如<t extends number comparable>></t> -
super仅允许出现在通配符中(如? super T),不能用于类型参数声明(<t super integer></t>是非法语法) -
? extends Object等价于?,但语义更明确;? super Object实际上只能是Object本身(因 Object 没有父类)
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











