在 java
里面,编译器不认识泛型,在 java
代码编译的时候,会进行类型擦除。
// 泛型类
public class A<T> {
public void test(T val)
{
System.out.println("class A " + val);
}
}
// 编译阶段,类型擦除后
public class A {
public void test(Object val)
{
System.out.println("class A " + val);
}
}
然后如果有一个类继承了上述泛型类:
public class B extends A<String> {
public void test(String val)
{
System.out.println("class B" + val);
}
}
// 类型擦除后
// 从以下代码可以看出
// B 实际还继承了另外一个方法
// test(Object val)
public class B extends A {
public void test(String val)
{
System.out.println("class B" + val);
}
}
然后疑问就发生在下面的代码中:
B b = new B();
A<String> a = b;
// a 变量引用的是 b实例
// 所以 调用 test 方法的时候
// 正常理解也应该调用 b 实例的 test 方法?
// 然而编译器在处理的时候却莫名其妙的
// 会在 B 类中产生一个桥方法(public void test(Object val) {this.test((String) val)})
// 然后实际调用的不是 B.test(String val)
// 而是上述桥方法
// 这是为什么呢?
a.test("one");
// 然后另外一个问题是
// 从上面可知 B 实际上继承了另外一个方法 A.test(Object val)
// 这是类型擦除后继承的
// 但是 下面的代码调用 却会报错!这是为什么?
a.test(20);
请耐心看上面代码注释中的问题描述 和 疑问,谢谢。核心问题有两个:
- 桥方法诞生的原因是啥(请结合上述例子做解释,谢谢)
- 类型擦除后继承的额外方法(
test(Object val)
)为什么调用后会报错?(请结合上述例子做解释,谢谢)
感谢 @huisexiaochou @Richard_Yi 两位回答,结合我参考的 Java中的类型擦除和桥方法 这篇文章,我终于理解了桥方法的诞生的原因 和 其他一些列泛型的疑问:
首先
java
中编译器是不认识泛型的,所以,泛型类 或 泛型方法在编译阶段会做类型擦除。非限定类型变量会用Object
替换。限定类型变量用 第一个限定类型替换。如下:
非限定类型变量类型擦除
限定类型变量类型擦除
有了类型擦除后,再来看看普通类的多态会发生什么现象。
从以上例子可以看出,多态中,当子类重写了超类方法时,则调用子类方法,否则都是调用超类方法!
现在我们再来看看加入了泛型类之后的结果是怎样的?