MST

星途 面试题库

面试题:Java多态向下转型与类型擦除的关系

结合Java泛型的类型擦除机制,阐述在使用泛型进行多态向下转型时会遇到哪些特殊情况,如何妥善处理?
32.1万 热度难度
编程语言Java

知识考点

AI 面试

面试题答案

一键面试

泛型的类型擦除机制

在Java中,泛型主要是在编译期提供类型安全检查,编译之后,所有的泛型信息都会被擦除,替换为对应的原始类型。例如,List<String>在编译后实际类型是ListString类型信息被擦除。

多态向下转型遇到的特殊情况

  1. 类型擦除导致运行时无法区分具体类型:由于类型擦除,在运行时JVM无法获取泛型的实际类型参数。例如,有两个类SubTypeA<T>SubTypeB<T>继承自SuperType<T>,当进行向下转型时,如SuperType<String> superObj = new SubTypeA<>(); SubTypeA<String> subObj = (SubTypeA<String>) superObj;,编译时因为泛型擦除,实际检查的是SuperTypeSubTypeA的继承关系,运行时无法确认泛型参数String,如果转型逻辑依赖于泛型参数类型,就会出现问题。
  2. ClassCastException风险:在泛型类型擦除后,当不恰当的向下转型时,容易抛出ClassCastException。比如,有List<String> strList = new ArrayList<>(); List<Integer> intList = (List<Integer>) strList;,编译期由于泛型擦除认为是合法的List类型转换,但运行时实际类型不匹配就会抛异常。

妥善处理方式

  1. 使用instanceof检查:在向下转型前,使用instanceof进行类型检查。例如:
SuperType<?> superObj = new SubTypeA<>();
if (superObj instanceof SubTypeA) {
    SubTypeA<?> subObj = (SubTypeA<?>) superObj;
    // 进行后续操作
}
  1. 增加类型标识字段:在泛型类中添加一个字段来标识实际类型。例如:
class SuperType<T> {
    private Class<T> type;
    public SuperType(Class<T> type) {
        this.type = type;
    }
    public Class<T> getType() {
        return type;
    }
}
class SubTypeA<T> extends SuperType<T> {
    public SubTypeA(Class<T> type) {
        super(type);
    }
}
// 使用时
SuperType<String> superObj = new SubTypeA<>(String.class);
if (superObj.getType() == String.class && superObj instanceof SubTypeA) {
    SubTypeA<String> subObj = (SubTypeA<String>) superObj;
    // 处理逻辑
}
  1. 借助反射:通过反射获取实际类型信息来辅助转型。例如:
SuperType<?> superObj = new SubTypeA<>();
if (superObj.getClass() == SubTypeA.class) {
    ParameterizedType genericSuperclass = (ParameterizedType) superObj.getClass().getGenericSuperclass();
    Type typeArg = genericSuperclass.getActualTypeArguments()[0];
    // 根据typeArg进行进一步的转型逻辑判断和处理
    SubTypeA<?> subObj = (SubTypeA<?>) superObj;
}