面试题答案
一键面试类型擦除的含义
在Java中,泛型是一种编译时特性。类型擦除指的是,在编译过程中,所有的泛型类型信息都会被擦除,只保留原始类型。编译器会在编译时根据泛型类型参数进行类型检查和转换,但在运行时,这些泛型类型信息并不存在。例如,List<String>
在运行时实际上是List
,String
类型信息被擦除。
对代码产生的影响
- 无法在运行时获取泛型类型信息:由于类型擦除,无法在运行时通过反射等机制获取泛型的实际类型参数。例如:
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
public class GenericTest {
private List<String> list = new ArrayList<>();
public static void main(String[] args) {
GenericTest test = new GenericTest();
Type type = test.getClass().getDeclaredField("list").getGenericType();
if (type instanceof ParameterizedType) {
ParameterizedType parameterizedType = (ParameterizedType) type;
Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
for (Type actualTypeArgument : actualTypeArguments) {
System.out.println(actualTypeArgument);
}
}
}
}
这段代码试图通过反射获取list
字段的泛型类型参数,但由于类型擦除,运行时无法获取到String
类型信息。
- 可能导致类型安全问题:如果在使用泛型时不小心绕过编译时检查,可能会在运行时出现类型转换异常。例如:
import java.util.ArrayList;
import java.util.List;
public class TypeSafetyIssue {
@SuppressWarnings("unchecked")
public static void main(String[] args) {
List list = new ArrayList();
list.add("hello");
List<Integer> intList = list;
int value = intList.get(0);
}
}
这里通过@SuppressWarnings("unchecked")
绕过了编译时检查,将List
赋值给List<Integer>
,运行时会抛出ClassCastException
,因为实际存储的是String
类型。
- 泛型方法和泛型类的静态成员:泛型类的静态成员不能使用泛型类的类型参数,因为静态成员属于类,在类加载时就已经确定,而类型擦除在编译时就发生了。例如:
class GenericClass<T> {
// 以下代码会编译错误
// static T staticField;
// static void staticMethod(T param) {}
}
- 桥接方法:在继承或实现泛型类型时,为了保持多态性,编译器会生成桥接方法。例如:
class GenericParent<T> {
public T get() { return null; }
}
class GenericChild extends GenericParent<String> {
@Override
public String get() { return "child"; }
}
编译器会为GenericClass
生成一个桥接方法public Object get()
,以确保在调用GenericParent
的方法时,能够正确调度到GenericChild
的get
方法。这是因为类型擦除后,GenericParent
的get
方法返回类型为Object
。