跳到主要内容

Java 泛型擦除机制(Type Reasure)

· 阅读需 2 分钟

Java 编译器在编译时会移除所有的泛型类型信息。

case1: 编译时 vs 运行时

// 编译时(源代码)
List<String> stringList = new ArrayList<String>();
List<Integer> intList = new ArrayList<Integer>();

// 运行时(字节码)- 泛型信息被擦除
List stringList = new ArrayList(); // 变成 Object
List intList = new ArrayList(); // 变成 Object

// 验证:运行时类型相同
System.out.println(stringList.getClass() == intList.getClass()); // true

case2: 泛型类型被替换

// 源代码
public class Box<T> {
private T value;

public T getValue() {
return value;
}
}

// 编译后等价于
public class Box {
private Object value; // T 被擦除为 Object

public Object getValue() {
return value;
}
}

case3: 有上界的泛型

// 源代码
public class NumberBox<T extends Number> {
private T value;

public T getValue() {
return value;
}
}

// 编译后等价于
public class NumberBox {
private Number value; // T 被擦除为上界类型 Number

public Number getValue() {
return value;
}
}

带来的问题:

  1. 无法获取泛型的类型
public class Test {
public <T> void printType(List<T> list) {
// ❌ 编译错误:无法获取 T 的实际类型
// System.out.println(T.class);

// ❌ 运行时只能获取到 List,不知道 T 是什么
System.out.println(list.getClass()); // class java.util.ArrayList
}
}
  1. 无法重载
public class Example {
// ❌ 编译错误:方法签名冲突
public void method(List<String> list) { }
public void method(List<Integer> list) { } // 擦除后签名相同
}

解决方案: 使用 hutoolcn.hutool.core.util.TypeUtil#getTypeArgument(java.lang.reflect.Type, int) 方法可以获取到泛型类型。

需要注意的是:Lambda 会丢失泛型信息,具体匿名内部类和实现类(public xxx implement xxx)不会。