MST

星途 面试题库

面试题:Java泛型类型擦除相关问题

请解释Java泛型中的类型擦除是什么意思?它会对代码产生哪些影响?请举例说明。
32.0万 热度难度
编程语言Java

知识考点

AI 面试

面试题答案

一键面试

类型擦除的含义

在Java中,泛型是一种编译时特性。类型擦除指的是,在编译过程中,所有的泛型类型信息都会被擦除,只保留原始类型。编译器会在编译时根据泛型类型参数进行类型检查和转换,但在运行时,这些泛型类型信息并不存在。例如,List<String>在运行时实际上是ListString类型信息被擦除。

对代码产生的影响

  1. 无法在运行时获取泛型类型信息:由于类型擦除,无法在运行时通过反射等机制获取泛型的实际类型参数。例如:
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类型信息。

  1. 可能导致类型安全问题:如果在使用泛型时不小心绕过编译时检查,可能会在运行时出现类型转换异常。例如:
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类型。

  1. 泛型方法和泛型类的静态成员:泛型类的静态成员不能使用泛型类的类型参数,因为静态成员属于类,在类加载时就已经确定,而类型擦除在编译时就发生了。例如:
class GenericClass<T> {
    // 以下代码会编译错误
    // static T staticField;
    // static void staticMethod(T param) {}
}
  1. 桥接方法:在继承或实现泛型类型时,为了保持多态性,编译器会生成桥接方法。例如:
class GenericParent<T> {
    public T get() { return null; }
}

class GenericChild extends GenericParent<String> {
    @Override
    public String get() { return "child"; }
}

编译器会为GenericClass生成一个桥接方法public Object get(),以确保在调用GenericParent的方法时,能够正确调度到GenericChildget方法。这是因为类型擦除后,GenericParentget方法返回类型为Object