e和t是泛型中约定俗成的类型参数标识符,非关键字;e代表element,常用于集合类如list,t代表type,更通用,适用于任意泛型场景。

泛型中的 E 和 T 是类型参数的命名约定,不是关键字,本质都是占位符;泛型擦除是 Java 为兼容旧版本字节码而采用的编译期机制,并非设计缺陷,而是权衡类型安全与 JVM 兼容性的结果。
E 和 T 的含义与使用场景
E(Element)常用于集合类,强调“元素”语义,比如 List<e></e>、ArrayList<e></e>,表示该集合存放的是某种类型的元素;T(Type)更通用,泛指任意具体类型,常见于工具类、容器包装类或泛型方法中,如 public <t> T getFirst()</t> 或 Box<t></t>。
二者没有语法区别,替换为 A、U 甚至 MyType 都能编译通过,但按惯例使用能提升可读性与协作效率。
- E 多见于 JDK 集合框架源码(如
AbstractCollection<e></e>) - T 更适合自定义泛型类或方法,尤其是不特指“集合元素”的场景(如
Result<t></t>、Mapper<t r></t>) - 实际开发中,一个类里通常只用一种主类型参数,避免混用 E/T 造成理解混乱
泛型擦除的底层原因
Java 在 1.5 引入泛型时,JVM 字节码规范已稳定多年,无法直接支持“运行时保留完整泛型信息”。为避免修改 JVM、破坏已有 class 文件兼容性,编译器选择在编译阶段将泛型类型擦除:所有 <string></string>、<integer></integer>、<t></t> 全部替换成其边界类型(无显式上界则为 Object),并插入必要的强制类型转换代码。
- 擦除后,
ArrayList<string></string>和ArrayList<integer></integer>在运行时都是同一个原始类型ArrayList - 方法签名中泛型参数不参与重载判断(如
void f(List<string>)</string>和void f(List<integer>)</integer>不能共存) - 反射可绕过编译检查添加非法类型(
list.add("abc")到List<integer></integer>),因为运行时已无类型约束
擦除带来的关键影响与应对思路
擦除不是“去掉类型”,而是把类型检查前移到编译期,用牺牲部分运行时能力换取向后兼容和轻量级实现。
- 无法在运行时获取泛型实际类型(
list.getClass().getTypeParameters()返回空数组) - 静态上下文中不能使用类型参数(
public static T instance;编译报错,因静态变量属于类而非实例,而擦除后类只有一个) - 不能创建泛型数组(
new T[10]不合法,因运行时不知道 T 是什么) - 通配符
?和边界extends Number>是擦除下保持一定灵活性的补充手段
本质上,Java 泛型是“编译期契约 + 运行时裸类型”的组合。理解 E/T 的语义约定有助于写出清晰 API,而看清擦除机制的动因与限制,才能避开陷阱、合理使用反射或 TypeReference 等变通方案。











