java泛型上限(? extends t)用于只读场景,保证安全读取t类型元素;下限(? super t)用于只写场景,保证安全写入t类型元素;二者均不改变继承关系,而由pecs原则指导选择。

Java 泛型的上限和下限,本质是通过 extends 和 super 对类型参数或通配符施加约束,控制“哪些类型能被接受”,而不是改变泛型本身的继承关系。关键不在“它是什么类型”,而在“它能安全做什么”。
上限:用 ? extends T 限定“能读不能写”
表示该泛型实际承载的是 T 或其任意子类,编译器只保证从中取出的元素一定是 T 类型(或其子类),因此可安全调用 T 的方法;但禁止写入任何具体值(包括 new T()),因为真实容器可能是更窄的子类列表,写入会破坏类型一致性。
-
✅ 安全操作:遍历、get() 获取元素、赋值给 T 或其父类型变量(如
List extends Number>中 get(0) 可赋给Number n = list.get(0)) - ❌ 禁止操作:add()、set()、addAll() 等任何写入动作(哪怕传 Integer 也会编译失败)
- 常见用途:只读场景,比如求和、打印、校验——即 PECS 中的 Producer(生产者)
下限:用 ? super T 限定“能写不能精读”
表示该泛型实际承载的是 T 或其任意父类,编译器只保证它一定能接收 T 类型的实例,因此可安全添加 T 及其子类对象;但从中读取时只能得到 Object(或最宽泛的共同父类),无法直接当 T 用,因为真实类型可能比 T 更宽泛(如 Object 或 Serializable)。
-
✅ 安全操作:add(T)、addAll(Collection
)、set(index, T),例如 List super Integer>可 add(42)、add(new Integer(1)) -
❌ 禁止操作:将 get(0) 直接赋给 Integer 变量(
Integer i = list.get(0)编译失败),只能赋给 Object - 常见用途:只写或收集场景,比如归并、填充、缓冲——即 PECS 中的 Consumer(消费者)
泛型类/方法声明中的 extends 和 super
在定义泛型类型参数时(如 <t extends number></t> 或 <t super integer></t>),语法上只支持 extends 作上界,不支持 super 用于类型形参声明(<t super integer></t> 是非法的)。下界限制仅适用于通配符 ? super T。
-
<t extends number></t>:T 必须是 Number 或其子类,可用于泛型类、接口、方法,如class Box<t extends comparable>&Serializable></t> - 多重上界:类必须写在最前,接口可多个,如
<t extends animal flyable swimmable></t> - 下界只能出现在通配符中,不能用于类型参数声明;想表达“接受更宽泛类型”的输入,就用
? super T作为方法参数类型
怎么选?看角色,不是看继承方向
别被“上界/下界”字面误导。真正决定用哪个的,是这个泛型参数在当前上下文里扮演的角色:
- 你要从它 拿东西出来用(比如 sum、toString、compareTo)→ 它是 Producer → 用
? extends T - 你要往它 塞东西进去存(比如 add、addAll、collect)→ 它是 Consumer → 用
? super T - 如果既读又写,通常说明设计不合理——要么拆成两个参数,要么直接用具体类型(如 List
)
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











