跳转至

什么是类型擦除?

面试回答

面试官: 什么是类型擦除?

你: 类型擦除就是Java泛型在编译期把类型参数抹掉,替换成原始类型或上界类型,并在使用的地方插入强制类型转换。说白了,泛型信息只活在编译阶段,字节码里没有,运行时压根不知道你写的是List<String>还是List<Integer>


为什么要擦除? 为了向后兼容。Java5引入泛型时,已经有海量的老代码在用List(原生类型)。如果把泛型带到运行期,所有老类库都得重写。擦除让泛型可以和原生类型混用,旧代码不用改就能跑在新版JVM上。


擦除规则:

  • 无限制类型参数 T → 擦成 Object

  • 有上界 T extends Comparable<T> → 擦成 Comparable

  • 泛型类中的字段和方法,类型参数在字节码层面就是擦除后的类型。

  • 调用泛型方法时,编译器自动插入 checkcast 指令,把取出来的 Object 强转回具体类型。这也是为什么你写 String s = list.get(0) 不用自己强转,但字节码里实际有强转。

  • 桥方法:为了实现多态,编译器可能会生成额外的桥接方法,保证擦除后仍然能正确重写。


擦除带来的问题:

  1. 运行期拿不到泛型类型。你没法判断一个 List 到底是 List<String> 还是 List<Integer>,只能用 instanceof 判断原生类型。

  2. 不能创建泛型数组。new T[10] 编译报错,因为运行期不知道 T 是啥。

  3. 方法签名冲突。比如 void add(List<String>)void add(List<Integer>) 擦除后都是 void add(List),不能重载。

  4. 基本类型不能用。只能写 List<Integer>,因为擦除后需要强转 Object,基本类型没法放到 Object 里,需要自动装箱。


时序图:编译器抹掉泛型

deepseek_mermaid_20260612_a5d676.png

一句话:泛型是编译器给的语法糖,运行时全是原生类型加一堆强制转换。