MST

星途 面试题库

面试题:Java泛型类型擦除与多态的交互问题

假设存在一个泛型类GenericClass<T>,其中有一个方法void print(T t)。再创建两个子类SubGenericClass1和SubGenericClass2继承自GenericClass,分别指定类型参数为String和Integer。当调用不同子类实例的print方法时,结合类型擦除机制,说明Java是如何实现多态的,以及可能会遇到什么问题?
32.6万 热度难度
编程语言Java

知识考点

AI 面试

面试题答案

一键面试

1. Java 如何通过类型擦除实现多态

在Java中,泛型是通过类型擦除机制来实现的。类型擦除意味着在编译阶段,所有的泛型类型信息都会被擦除,替换为它们的原始类型(raw type)。

对于 GenericClass<T>,擦除后变为 GenericClass,其 print(T t) 方法变为 print(Object t)

SubGenericClass1 继承 GenericClass<String> 时,在字节码层面,它的 print(String t) 方法实际上是 print(Object t),但由于Java的方法重写机制,在运行时,JVM会根据对象的实际类型来调用正确的方法。即当 SubGenericClass1 的实例调用 print 方法时,会调用 SubGenericClass1 中重写的 print(String t) 方法(尽管字节码层面是 print(Object t)),这就实现了多态。

同理,SubGenericClass2 继承 GenericClass<Integer>,字节码层面 print(Integer t) 变为 print(Object t),但运行时根据对象实际类型调用 SubGenericClass2 中重写的 print(Integer t) 方法。

2. 可能遇到的问题

  • 类型安全性降低:由于类型擦除,在运行时无法获取泛型的实际类型参数。这可能导致在运行时发生 ClassCastException。例如,如果在使用泛型时不小心将错误类型的数据放入集合中,编译时不会报错,但运行时可能会因为类型转换失败而抛出异常。
  • 桥接方法问题:在某些复杂的继承和泛型组合场景下,编译器可能会生成桥接方法(bridge method)来维护多态性。这些桥接方法可能会使字节码变得复杂,并且在调试和理解代码时增加难度。例如,当子类重写父类的泛型方法并且返回类型是协变的(子类型)时,编译器会生成桥接方法来确保多态性的正确实现。但这种情况下,开发者可能会看到一些看似多余或难以理解的方法调用,因为桥接方法在字节码层面做了额外的处理。