Java 类型擦除
在学习Java泛型时,"类型擦除"是一个非常重要但又容易被忽视的概念。理解类型擦除对于正确使用泛型、避免一些常见陷阱至关重要。本文将带你深入了解Java类型擦除的机制与影响。
什么是类型擦除?
类型擦除(Type Erasure)是Java泛型实现的核心机制。简单来说,类型擦除指的是Java编译器在编译过程中,会去掉(擦除)代码中的泛型信息,用具体类型(通常是Object或泛型的边界类型)替代。这样做的目的是为了保持与Java 5之前的代码兼容。
历史背景
Java 5引入泛型时,为了保证向后兼容性(不破坏已有的代码和类库),采取了类型擦除的实现方式。这与C++等语言的泛型实现方式不同,C++的模板在编译时会为每种类型生成不同的代码。
类型擦除的基本原理
类型擦除主要包含以下几个方面:
- 替换泛型参数:无边界的类型参数(如
<T>
)会被替换为Object
- 替换有边界的类型参数:有边界的类型参数(如
<T extends Number>
)会被替换为第一个边界类型(此例中为Number
) - 插入必要的类型转换:在 必要的地方插入强制类型转换,以保持代码类型安全
- 生成桥接方法:必要时创建桥接方法维护多态
让我们通过一个例子来理解:
// 编译前的代码
public class Box<T> {
private T value;
public void setValue(T value) {
this.value = value;
}
public T getValue() {
return value;
}
}
经过类型擦除后,编译器会将代码转换为:
// 编译后的代码(类型擦除后)
public class Box {
private Object value;
public void setValue(Object value) {
this.value = value;
}
public Object getValue() {
return value;
}
}
带有边界的泛型与类型擦除
当泛型有边界时,擦除会使用边界类型代替:
// 编译前的代码
public class NumberBox<T extends Number> {
private T value;
public void setValue(T value) {
this.value = value;
}
public T getValue() {
return value;
}
}
类型擦除后:
// 编译后的代码(类型擦除后)
public class NumberBox {
private Number value;
public void setValue(Number value) {
this.value = value;
}
public Number getValue() {
return value;
}
}