面试题答案
一键面试1. Java泛型在编译阶段类型擦除的具体过程
- 基本规则:Java泛型是在编译期实现的,编译器在编译时会进行类型擦除。具体来说,编译器会将泛型类型替换为其上限(如果指定了上限,默认上限是
Object
)。 - 泛型类型参数的擦除:对于泛型类
class Generic<T> {}
,在编译后,类型参数T
会被擦除,实际类型变成Object
。例如,List<Integer>
中的Integer
类型参数会被擦除。 - 泛型方法的擦除:对于泛型方法
public <T> void method(T t) {}
,编译后类型参数T
也会被擦除,方法变为public void method(Object t) {}
。如果泛型方法指定了上限public <T extends Number> void method(T t) {}
,擦除后变为public void method(Number t) {}
。
2. List<Integer>
在类型擦除后变成了什么
List<Integer>
在类型擦除后变成了List
,即原始类型。具体来说,所有对Integer
类型的引用都被替换为对Object
类型的引用。例如,原本获取List<Integer>
中元素的代码Integer num = list.get(0);
,在擦除后实际执行的代码类似Object obj = list.get(0); Integer num = (Integer) obj;
。
3. 对泛型代码运行的影响
- 优点
- 向后兼容性:由于类型擦除,Java泛型可以与旧版本的Java代码(没有泛型)兼容。这使得在引入泛型的同时,已有的代码库无需进行大规模修改就能继续使用。
- 性能无损耗:在运行时没有额外的类型信息,因此不会因为泛型而增加运行时的开销。
- 缺点
- 运行时类型检查缺失:由于类型信息在编译期被擦除,运行时无法获取泛型的实际类型。例如,
List<Integer>
和List<String>
在运行时是同一个类型,这可能导致在运行时出现ClassCastException
。如果向一个List<Integer>
中错误地添加了一个String
对象(绕过编译器检查的情况下),在获取元素并强制转换为Integer
时就会抛出异常。 - 无法创建泛型数组:因为类型擦除,
new T[]
这种创建泛型数组的操作是不允许的。例如List<Integer>[] listArray = new List<Integer>[10];
是不合法的,只能使用List[] listArray = new List[10];
,但这样就失去了泛型的类型安全性。
- 运行时类型检查缺失:由于类型信息在编译期被擦除,运行时无法获取泛型的实际类型。例如,