MST

星途 面试题库

面试题:Java泛型中类型擦除与继承关系的交互

在Java中,泛型存在类型擦除机制。假设有一个泛型类`GenericClass<T>`,以及它的子类`SubGenericClass extends GenericClass<String>`。当进行类型擦除后,`SubGenericClass`在字节码层面的继承关系是怎样的?请说明类型擦除如何影响泛型类及其子类的继承关系,并举例说明可能出现的问题。
31.8万 热度难度
编程语言Java

知识考点

AI 面试

面试题答案

一键面试
  1. 字节码层面的继承关系
    • 在Java的类型擦除机制下,泛型类型参数T在编译后会被擦除。对于GenericClass<T>,擦除后变为GenericClass,对于SubGenericClass extends GenericClass<String>,擦除后变为SubGenericClass extends GenericClass。所以在字节码层面,SubGenericClass继承自擦除类型后的GenericClass
  2. 类型擦除对继承关系的影响
    • 编译时的强类型检查丢失:编译时依靠泛型进行的强类型检查,在运行时由于类型擦除而不存在。例如,在编译时GenericClass<String>只能操作String类型的数据,但运行时擦除后,可以向其添加其他类型的数据(当然,这会导致运行时错误)。
    • 桥接方法的产生:为了保证多态性,在泛型子类中会产生桥接方法。比如当子类重写父类基于泛型的方法时,由于类型擦除,为了保持多态行为的正确性,编译器会生成桥接方法。
  3. 举例说明可能出现的问题
    • 运行时类型错误
import java.util.ArrayList;
import java.util.List;

class GenericClass<T> {
    private T value;
    public void setValue(T value) {
        this.value = value;
    }
    public T getValue() {
        return value;
    }
}

class SubGenericClass extends GenericClass<String> {
    @Override
    public void setValue(String value) {
        super.setValue(value);
    }
}

public class Main {
    public static void main(String[] args) {
        SubGenericClass sub = new SubGenericClass();
        GenericClass gc = sub;
        // 编译时不会报错,但运行时会抛出ClassCastException
        gc.setValue(10); 
        String result = sub.getValue(); 
    }
}
  • 在上述代码中,由于类型擦除,gc.setValue(10)编译时不会报错,因为擦除后GenericClasssetValue方法参数变为Object类型。但在运行时,sub.getValue()期望返回String类型,而实际返回的是Integer,就会抛出ClassCastException
  • 桥接方法相关问题(以重写泛型方法为例)
class GenericBase<T> {
    public T get() {
        return null;
    }
}

class GenericSub extends GenericBase<String> {
    @Override
    public String get() {
        return "Hello";
    }
}
  • 在字节码层面,编译器会为GenericSub类生成一个桥接方法public Object get(),这个桥接方法内部调用public String get()方法。如果在反射调用等场景下不小心使用了这个桥接方法,可能会导致与预期不符的行为。