Java泛型通过上界(extends)和下界(super,仅通配符)实现类型限定:上界<T extends X>支持子类型、多边界及方法调用;下界<? super T>仅用于通配符,适用于写入场景。

Java 中通过 上界(extends) 和 下界(super,仅限通配符) 两种方式实现类型限定,核心目标是让泛型代码既能保持灵活性,又能在编译期获得类型安全和方法调用能力。
用 extends 声明上界:限制为某类或接口的子类型
上界是最常用、最直接的限定方式,语法为 <T extends X>。这里的 extends 是广义的——既表示继承父类,也表示实现接口。
- 允许调用边界类型声明的方法,比如
T extends Number后可放心调用t.doubleValue() - 支持多边界,格式为
<T extends A & B & C>,其中A必须是类且排在最前,B、C等必须是接口 - 可用于泛型类、泛型接口、泛型方法的类型参数声明
- 示例:一个求最大值的泛型方法要求元素可比较
public static <T extends Comparable<T>> T max(List<T> list) { ... }
用 ? super T 实现下界:只适用于通配符,用于“写入”场景
Java 不允许对类型参数本身写 <T super X>(编译报错),但允许用通配符 ? super X 表达“接受 X 及其所有父类型”的语义。
你接手一个需求时,是不是经常这样:"改一个小字段 → 结果把不相关的代码也改了"、"需求说得很模糊 → 做着做着发现跑偏了"、"数据库加个字段 → 上线才发现漏了数据兼容"、"做了个新功能 → 一个月后自己都忘了当时怎么设计的"、"写到一半被中断 → 再回来不知道从哪继续";这个 Skill 就是专门解决这些问题的。 它会自动探测你的项目环境(JDK、Spring Boot、ORM、数据库、前端框架),记在
- 典型用途是向集合中添加数据(PECS 原则中的 Consumer)
- 你可以往
List<? super Integer>里加Integer或它的子类(如1、new Long(5)不行,因为Long不是Integer的子类),但读取时只能当作Object - 常见于工具方法,如
Collections.addAll(Collection<? super T>, T...)
泛型方法中独立声明带边界的类型参数
方法级泛型可脱离所在类是否泛型而单独定义,适合封装通用逻辑。
立即学习“Java免费学习笔记(深入)”;
- 语法位置在返回类型前:
public static <T extends Number> double sum(List<T> nums) { ... } - 该方法不依赖外部类的类型参数,也不影响其声明;多个方法可各自定义不同边界
- 边界越具体,可用操作越多,但复用性可能下降;例如
<T extends Number & Serializable>同时约束数值行为与序列化能力
实际编码中容易忽略的关键点
边界不是注释,它直接影响类型擦除后的字节码和编译器允许的操作。
- 没加边界时,
T擦除为Object,只能调用Object的方法 - 加了
extends Number后,擦除为Number,编译器会插入桥接方法并确保doubleValue()等调用合法 - 误把
super用于类型参数声明(如<T super String>)会导致编译失败 - 通配符的上下界不能共存(
? extends X & super Y不合法)

















