面试题答案
一键面试Java泛型中的类型擦除机制
- 定义:Java的泛型是在编译期实现的,类型擦除指的是在编译过程中,将泛型类型信息擦除,把所有的泛型参数替换为它们的限定类型(通常是Object,除非有明确的上界)。
- 实现方式:编译器在编译时会执行以下操作:
- 替换所有泛型类型参数为它们的上界类型(如果有),否则为Object。
- 插入必要的类型转换代码,以确保类型安全。
对泛型类和方法的影响
- 泛型类:
- 编译后:泛型类的字节码中不再包含泛型类型信息。例如,
List<String>
和List<Integer>
编译后的字节码类型都是List
,在运行时无法区分它们。 - 示例:
- 编译后:泛型类的字节码中不再包含泛型类型信息。例如,
List<String> stringList = new ArrayList<>();
stringList.add("hello");
// 编译后实际执行的代码类似如下
List stringList = new ArrayList();
stringList.add("hello");
String str = (String) stringList.get(0);
- 泛型方法:
- 编译后:泛型方法的泛型参数同样被擦除,方法签名只保留原始类型。
- 示例:
public static <T> T getFirst(List<T> list) {
return list.get(0);
}
// 编译后
public static Object getFirst(List list) {
return list.get(0);
}
桥接方法
- 定义:桥接方法是编译器自动生成的方法,用于在泛型类型擦除后,维护多态性。当一个泛型类实现了一个泛型接口或者继承了一个泛型类,并且重写了其中的泛型方法时,编译器会生成桥接方法。
- 作用:在类型擦除后,保证重写方法的多态性仍然有效。因为类型擦除后,重写方法的签名在字节码层面看起来可能与接口或父类中的方法签名不一致,桥接方法可以解决这个问题。
- 示例:
class MyList<T> implements List<T> {
@Override
public boolean add(T e) {
// 实际实现
return true;
}
}
在上述代码中,List
接口中的add
方法在类型擦除后是boolean add(Object e)
,而MyList
类中的add
方法擦除后是boolean add(Object e)
,为了保证多态性,编译器会生成一个桥接方法:
public boolean add(Object e) {
return add((T) e);
}
这个桥接方法在运行时,会将Object
类型的参数转换为实际的泛型类型T
,然后调用实际的add
方法,从而保证了多态性的正确性。