面试题答案
一键面试1. 泛型类型擦除对方法重写的影响
在Java中,泛型是通过类型擦除实现的。这意味着在运行时,泛型类型信息会被擦除,只保留原始类型。这会对方法重写产生以下影响:
- 签名一致性:重写方法的签名(除了返回类型可以是协变的)必须与被重写方法完全一致。由于类型擦除,泛型参数化类型在运行时不存在,可能导致看似不同的泛型方法在擦除后具有相同的签名,从而引发编译错误。
- 桥接方法:为了保证多态性在泛型存在时的正确性,编译器会生成桥接方法。这些桥接方法用于在运行时适配擦除后的类型。
2. 多层继承且包含泛型的类结构示例
class Animal {}
class Dog extends Animal {}
class Cat extends Animal {}
class GenericBase<T> {
public void show(T t) {
System.out.println("GenericBase show: " + t);
}
}
class SubGeneric1<T extends Animal> extends GenericBase<T> {
@Override
public void show(T t) {
System.out.println("SubGeneric1 show: " + t);
}
}
class SubGeneric2 extends SubGeneric1<Dog> {
@Override
public void show(Dog dog) {
System.out.println("SubGeneric2 show: " + dog);
}
}
3. 方法重写情况分析
GenericBase
与SubGeneric1
:SubGeneric1
重写了GenericBase
的show
方法。由于SubGeneric1
的泛型参数T
是Animal
的子类型,这是合法的重写。在编译和运行时,类型擦除不会影响这种重写关系,因为擦除后方法签名仍然匹配。SubGeneric1
与SubGeneric2
:SubGeneric2
继承自SubGeneric1<Dog>
并重写了show
方法。从泛型角度看,show(Dog dog)
似乎是一个更具体的重写。但由于类型擦除,在运行时SubGeneric1
的show
方法擦除后变为show(Animal t)
,而SubGeneric2
的show
方法擦除后也是show(Animal t)
。为了保证多态性,编译器会生成桥接方法。例如,编译器会为SubGeneric2
生成一个桥接方法show(Animal t)
,该方法内部调用show(Dog dog)
。这样,在多态调用时,即使实际类型被擦除,也能正确调用到SubGeneric2
的具体实现。
4. 边界问题总结
- 签名冲突:泛型类型擦除可能导致方法签名冲突,使得原本看似合法的重写变为非法。开发人员需要确保在类型擦除后,重写方法的签名仍然与被重写方法一致。
- 桥接方法理解:开发人员需要理解桥接方法的生成机制,特别是在复杂的泛型继承体系中。桥接方法是保证泛型多态性的关键,但也可能增加代码理解和调试的难度。
- 协变返回类型:在重写方法时,返回类型可以是协变的,但要注意与类型擦除的结合。如果返回类型涉及泛型,需要确保擦除后不会破坏协变关系。