java桥接方法理解

176 阅读2分钟

问题

java为什么会在泛型类的子类生成桥接方法

分析

存在两个类,泛型类A,泛型类A的子类B

泛型类A

/**
 * @author xunxing
 */
public class A<T> {
    public Integer test(T val) {
        System.out.println(val);
        return 0;
    }
}

泛型类B

/**
 * @author xunxing
 */
public class B extends A<String> {

    @Override
    public Integer test(String val) {
        System.out.println("test val");
        return 1;
    }

    public static void main(String[] args) {
        A<String> a = new B();
        a.test("2");
    }
}

在java里,编译器不认识泛型,在java代码编译的时候,会进行类型擦除,我们通过反编译看下类型擦除

泛型类A的反编译

可以看出A的test方法,出参是java/lang/Integer,入参是java/lang/Object,对入参泛型T进行擦除变成Object

泛型类B的反编译

原因

泛型类存在类型擦除的情况,导致A类实际上仅有test(Object)方法,B类只有test(String)方法实际上并没有重写A类的test(Object)方法,很显然这并不是重写,重写是子类对父类的允许访问的方法的实现过程进行重新编写, 返回值和形参都不能改变,类型擦除和重写产生的冲突。

java语言的开发者们想到的办法是通过在 B 类中合成一个桥方法来解决这个冲突,桥接方法是对A类 test(Object)方法的覆写,并且函数体调用的是B类的 test(String) 方法,通过B生成桥接方法的反编译可以看出

泛型经过类型擦除会多出桥接方法的坑

**原因:**子类没有指定Integer泛型参数,父类的泛型方法setData(T data)在泛型擦除后是setData(Object data),子类中入参是Integer的setData方法被当作了新方法。因为子类的setData方法没有增加@Override注解,因此编译器没能检测到重写失败的问题

**解决:**方法重写一定要标记@Override注解,可以直接在编译的时候检查出

例子: