java object转泛型_Java泛型(二):类型擦除与泛型翻译

05a24b9f2364266de8aa8d3adc996a5b.png

之前的文章,我们介绍了Java泛型的基本使用,这里我们将深入到编译期、虚拟机层面当中去。具体地,将会分析介绍类型擦除、泛型翻译方面的内容

类型擦除

在Java虚拟机JVM中是没有泛型这一说的,Java的泛型在编译期会被去除,即所谓的类型擦除。擦除后类型变量将由raw type原始类型来代替,具体地,如果泛型的类型变量上有类型限定,则第一个限定类型即为raw type,否则raw type为Object

/**

这里,我们对Pair类的Class文件反编译,由于Pair的类型变量T上没有类型限定,则类型擦除后该类型变量T将由Object代替,从下图红框我们也可以看到该类的first、second属性已经由T替换为Object了;而泛型方法minmax的类型变量T由于类型限定,故将使用第一个限定类型Comparable来作为raw type进行替换

54c97849a41f592ae0e948b73f643c3f.png

泛型翻译

由于Java的类型擦除机制,使得泛型类在编译后可以认为就是一个普通的Java类,那如何保证类型正确呢?比如这里testPair1方法中getFirst、getSecond,由于类型擦除机制的存在,其应该返回的是Object类型,讲道理,不应该允许直接赋给String类型的变量啊

// 测试泛型类

其实,道理很简单,虽然字节码中的类型是Object了,但是编译器在调用这些方法的同时,会适当的自动的插入强制转换的指令,我们对该方法进行反编译,即可看到checkcast字节码指令

f66e533b8a37c6e681144cd7011f8ca9.png

现在我们来介绍另外泛型翻译的情形——Bridge Method 桥方法。这里,提供了一个Pair的继承类

public 

很明显,NumPair的setFirst方法是重写了父类的setFirst方法。但是由于类型擦除机制的存在,父类的setFirst方法的参数first其类型由T已经变为了Object,这一点从反编译后的结果也可以看出来。那么现在问题就来了,父类的方法签名是setFirst(Object first),而子类中该方法签名是setFirst(Integer first),二者不一样。目前看上去,类型擦除机制好像是与多态发生了冲突

2e111a84cc784cd0385cdaf0707bb61c.png

我们先测试下,看看类型擦除机制与多态是否存在冲突

public 

通过打印输出,我们可以确定子类的setFirst被正确地调用了,咦?多态与类型擦除机制二者之间好像又没有冲突了,而是父类与子类的setFirst方法之间签名确实不一样啊,这到底是怎么回事呢?

40cf10646ac51dc3452685e17c30f4fb.png

其实道理很简单,还是老办法,我们对子类的字节码文件进行反编译来一探究竟,从下图可以看出,编译器不仅生成我们所提供的setFirst(Integer first)方法,还帮我们自动生成了一个签名为setFirst(Object first)的新方法(如下图蓝框所示)。其实确实是由于类型擦除的原因,导致我们重写方法与父类方法在编译之后出现了签名不一致的情况。编译器为了解决这个冲突,使得多态特性不被破坏。其会自动生成一个与父类签名一致的方法setFirst(Object first),并在其内部去调用我们期望的setFirst(Integer first)方法。由于这个编译器自动生成的方法,一方面是负责来实际重写父类方法的,另一方面则是为了调用开发者实际提供的重写方法,故其被形象地称之为Bridge Method 桥方法

f4722a8565768e7c560c4110238d0b26.png

参考文献

  1. Java核心技术·卷I 凯.S.霍斯特曼著
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值