泛型类型擦除(Generics Type Erasure)是Java泛型实现的核心机制,它是指在编译期间将泛型类型信息移除或"擦除"的过程。
类型擦除的基本原理
-
编译时检查,运行时擦除:Java泛型只在编译阶段有效,在编译后的字节码中不包含泛型类型信息。
-
擦除规则:
-
无界类型参数(
<T>
)会被替换为Object
-
有界类型参数(
<T extends Number>
)会被替换为边界类型(这里是Number
) -
泛型方法中的类型参数也会被擦除
-
类型擦除的示例
// 源代码
public class Box<T> {
private T value;
public void set(T value) {
this.value = value;
}
public T get() {
return value;
}
}
// 编译后等效代码
public class Box {
private Object value;
public void set(Object value) {
this.value = value;
}
public Object get() {
return value;
}
}
类型擦除带来的影响
-
无法使用instanceof检查泛型类型:
if (list instanceof List<String>) // 编译错误
-
不能创建泛型数组:
T[] array = new T[10]; // 编译错误
-
不能直接创建泛型实例:
T obj = new T(); // 编译错误
-
静态成员共享:同一个类的不同泛型实例共享相同的静态成员
桥接方法(Bridge Methods)
为了保持多态性,编译器会生成桥接方法:
// 源代码
interface Comparable<T> {
int compareTo(T o);
}
class String implements Comparable<String> {
public int compareTo(String o) { ... }
}
// 编译器生成的桥接方法
public int compareTo(Object o) {
return compareTo((String) o);
}
类型擦除的优点
-
保持与旧版本Java的兼容性
-
减少运行时开销
-
简化JVM实现
绕过类型擦除的限制
虽然类型擦除移除了大部分类型信息,但可以通过以下方式保留部分信息:
-
使用Class对象:
public class Box<T> { private Class<T> type; public Box(Class<T> type) { this.type = type; } public boolean isInstance(Object obj) { return type.isInstance(obj); } }
-
通过方法参数传递类型信息:
public static <T> T createInstance(Class<T> type) { return type.newInstance(); }
类型擦除是Java泛型实现的核心机制,理解它有助于更好地使用泛型并避免一些常见的陷阱。