java泛型类型擦除的核心是编译期移除泛型参数,无界泛型(如)统一擦除为object,有界泛型擦除为首个上界类型;编译器插入强制转换和类型检查以保障运行时安全,确保与旧版jvm及代码完全兼容。

Java 泛型的类型擦除,核心是编译器在生成字节码时主动“拿掉”泛型类型参数,让 JVM 运行时看不到 `
Object 是无界泛型擦除后的实际类型
当你写 class Box<t> { T value; }</t>,T 没有任何 extends 限定,编译器就认定它的上界是 Object。编译完成后,整个类等效于:
class Box { private Object value; }-
public T get()变成public Object get() -
public void set(T value)变成public void set(Object value)
也就是说,运行时 Box
擦除不是丢弃,而是用 Object 承载 + 编译器补转换
类型擦除不等于类型丢失。编译器会做两件事来保住类型安全:
- 在调用泛型方法返回值的地方,自动插入强制转换。比如
String s = box.get();编译后变成先调Object o = box.get();,再加一条checkcast String字节码指令 - 在往泛型集合或容器中存值时,编译器检查实参是否符合声明类型(如只允许 add(String) 到 List
),但运行时底层仍是 Object 数组或 Object 字段
所以 Object 是承载数据的“容器底座”,而类型约束由编译器在前端把关。
有上界时,Object 就会被更具体的类型替代
一旦你写了边界,擦除目标就不再是 Object:
-
<t extends number></t>→ 擦除为Number -
<e extends runnable cloneable></e>→ 擦除为第一个接口Runnable -
<k extends comparable>></k>→ 擦除为Comparable
只有当没写任何 extends 时,Object 才成为默认兜底。这也是为什么泛型方法 <t> T pick(T a, T b)</t> 编译后参数和返回值都是 Object。
为什么非得选 Object?兼容性是硬要求
Java 5 引入泛型时,必须让新代码能和 JDK 1.4 及更早版本的类库无缝协作。ArrayList 在泛型之前就是基于 Object 实现的:
- 旧代码:
ArrayList list = new ArrayList(); list.add("x"); String s = (String) list.get(0); - 新代码:
List<string> list = new ArrayList(); list.add("x"); String s = list.get(0);</string>
两者最终都操作同一个原始类型 ArrayList,底层都是 Object[]。Object 作为擦除目标,保证了泛型只是“编译期增强”,而非“运行时重构”。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











