java泛型 java处理泛型擦除和多态中矛盾的桥方法方案

问题引出

泛型父类

public class GenericityErasure<T> {
    public T f1(T t){
        System.out.println("f1");
        return t;
    }
    public T f2(T t){
        System.out.println("GenericityErasure.f2");
        return t;
    }
    public Object f3(Object o){
        System.out.println("GenericityErasure.f3");
        return o;
    }
}

子类复写泛型方法 f1

public class GenericityErasureSub extends GenericityErasure<Date> {

    public Date f1(Date localDate) {
        System.out.println("sub");
        return localDate;
    }
    public Object f3(Date o) {
        System.out.println("GenericityErasureSub.f3");
        return o;
    }
}

上层调用代码

class GenericityErasureSubTest {
    @Test
    void GenericityErasureSub() {
        GenericityErasureSub sub = new GenericityErasureSub();
        GenericityErasure father = null;
        father = sub;

        sub.f1(new Date());
        father.f1(new Object());
        father.f1(new Date());

        father.f3(new Object());
        father.f3(new Date());
        sub.f3(new Object());
        sub.f3(new Date());

    }
}

出现问题:

GenericityErasureSub.java:11 是找个类声明的行。

问题总结:

1、f3方法属于重载运行时能够区分调用不同的方法,为啥泛型擦除后的f1方法不行呢?

2、类型转换异常是具体走到哪行代码抛出的呢?为啥在类头上标记位置呢?

问题分析

以此查看这三个类生成的字节码文件,其中泛型子类的的字节码有点不一致。

idea上的字节码如下:

public class lxf/experiment/hashcode/GenericityErasureSub extends lxf/experiment/hashcode/GenericityErasure {

  // compiled from: GenericityErasureSub.java

  // access flags 0x1
  public <init>()V
   L0
    LINENUMBER 11 L0
    ALOAD 0
    INVOKESPECIAL lxf/experiment/hashcode/GenericityErasure.<init> ()V
    RETURN
   L1
    LOCALVARIABLE this Llxf/experiment/hashcode/GenericityErasureSub; L0 L1 0
    MAXSTACK = 1
    MAXLOCALS = 1

  // access flags 0x1
  public f1(Ljava/util/Date;)Ljava/util/Date;
   L0
    LINENUMBER 14 L0
    GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
    LDC "sub"
    INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V
   L1
    LINENUMBER 15 L1
    ALOAD 1
    ARETURN
   L2
    LOCALVARIABLE this Llxf/experiment/hashcode/GenericityErasureSub; L0 L2 0
    LOCALVARIABLE localDate Ljava/util/Date; L0 L2 1
    MAXSTACK = 2
    MAXLOCALS = 2

  // access flags 0x1
  public f3(Ljava/util/Date;)Ljava/lang/Object;
   L0
    LINENUMBER 18 L0
    GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
    LDC "GenericityErasureSub.f3"
    INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V
   L1
    LINENUMBER 19 L1
    ALOAD 1
    ARETURN
   L2
    LOCALVARIABLE this Llxf/experiment/hashcode/GenericityErasureSub; L0 L2 0
    LOCALVARIABLE o Ljava/util/Date; L0 L2 1
    MAXSTACK = 2
    MAXLOCALS = 2

  // access flags 0x1041
  public synthetic bridge f1(Ljava/lang/Object;)Ljava/lang/Object;
   L0
    LINENUMBER 11 L0
    ALOAD 0
    ALOAD 1
    CHECKCAST java/util/Date
    INVOKEVIRTUAL lxf/experiment/hashcode/GenericityErasureSub.f1 (Ljava/util/Date;)Ljava/util/Date;
    ARETURN
   L1
    LOCALVARIABLE this Llxf/experiment/hashcode/GenericityErasureSub; L0 L1 0
    MAXSTACK = 2
    MAXLOCALS = 2
}

第一眼不容易看出问题(注意看最后的方法)。通过javap 查看:

 子类中只有一个f1方法,但是字节码文件中竟然多了一个f1方法。

问题总结:

为了解决泛型方法被子类复写,然后泛型的特性跟java多态的冲突。java在编译阶段重新自动复写了父类的方法,进行强制类型转换后调用子类的方法。

这个编译器自动生成的方法叫做桥方法。做的事情就是入参类型强制转换,然后调用子类的方法。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值