T是类型参数声明,用于定义泛型类/方法;?是类型通配符,用于安全使用泛型实例。T在尖括号中引入、可命名约束、参与推导;?仅出现在使用位置,不可定义泛型,限制读写操作。

在 Java 泛型中,T 和 ?(问号)看起来都表示“某种类型”,但语义完全不同:前者是**类型参数声明**,后者是**类型通配符**;一个用于定义泛型结构,一个用于使用泛型实例。
T 是类型参数,用于泛型类/方法的定义
T(或任意标识符如 E、K)是类型形参,在泛型声明处引入,代表一个待确定的具体类型。它有名字、可被多次引用、支持边界限定,并参与类型推导。
- 出现在尖括号中:
class Box<T> { ... }、<T> T pick(T a, T b) { ... } - 可在类/方法体内反复使用:
private T value;、return (T) obj; - 可加约束:
<T extends Comparable<T>>或<T super Number> - 编译时会被擦除,但类型关系在编译期受检(如
Box<String>与Box<Integer>不兼容)
? 是通配符,用于变量/参数的类型声明
? 不是类型名,也不引入新类型变量,而是对已有泛型类型的**安全读写限制表达式**。它只出现在使用位置(如变量类型、形参类型、返回类型),不能用于定义泛型类或方法。
- 合法:
List<?> list = new ArrayList<String>();、void print(List<? extends Number> nums) { ... } - 非法:
class Container<?> { ... }(语法错误)、<?> foo() { ... }(不能用 ? 做类型参数) - 不可实例化:
new ArrayList<?>()编译失败(? 没有具体类型信息) - 受限写入:
List<?>只能 addnull;List<? extends Number>不能 add 任何对象(除了 null);List<? super Integer>可 addInteger及其子类
关键区别:作用域与用途不可互换
T 属于“定义侧”(defining side),回答“这个泛型结构能适配哪些类型”;? 属于“使用侧”(using side),回答“这个泛型实例能安全接受哪些操作”。二者不在同一抽象层级。
- 你不能用
?替代方法签名中的<T>—— 那会失去类型一致性(比如无法保证返回值和参数是同一类型) - 你也不能在变量声明中写
Box<T> box;而不先定义T—— 此时T是未声明的符号,编译报错;必须用Box<?>或具体类型如Box<String> - 常见误用:
List<?> list = new ArrayList<?>();❌(右边非法);正确写法是List<?> list = new ArrayList<String>();
一句话总结
T 是占位符名字,用来定义泛型契约;? 是匿名匹配模式,用来安全消费泛型实例。 前者赋予类型可重用性,后者保障类型安全性 —— 它们协同工作,但角色严格分离。















