java泛型表达式和方法工作原理小结
2016-02-18 14:46
453 查看
java翻译泛型方法原理小结
在java的虚拟机中并不存在实际的泛型类,而是将所有的泛型类编译成一个原始类型(raw type),也就是所谓的类型擦除,简单的说,从程序员的角度来看普通的泛型类应该是一族类,而在虚拟机看来,所有泛型类都是一个原始类(不支持实际意义上的泛型类),而几乎所有的泛型功能都通过编译器来映射成字节码,而与虚拟机无关之所以虚拟机不支持实际意义上的泛型类,是由于早期的泛型类是由继承产生的,这样做也同样带来一个好处,即不会产生如c++那样的代码膨胀。
当翻译一个泛型表达式时实际上编译器将翻译两条虚拟机指令:
调用原始类的方法
将原始类强制转换成
例如:
Pair<Employee> buddies = ...; Employee buddy = buddies.getFirst();
以上取自java核心技术,但是按照对之前文章的理解,在这两步之前应该还有类型检查,即当你使用
<Employee>时会检查buddies是否是Employee类型,当然这一部也会由编译器翻译成字节码完成,而无需程序猿了解原理。
当泛型方法被类型擦除的适合会出现一些复杂的问题。首先一个是对于超类方法的调用:
请看如下的示例:
class DateInterval extend Pair<Date> { public void setSecond(Date second) { if(second.compareTo(getFirst())>=0 supper.setSecond(second); } }
其中Pair是一个Date对象,需要覆盖这个方法的类第二个值永远不小于第一个值。当类型擦除的时候从虚拟机看来这个代码变成如下形式:
class DateInterval extend Pair { public void setSecond(Date second) { } }
但是经过类型擦除的方法和原先的原始类型的方法有什么不同呢?
class DateInterval extend Pair { public void setSecond(Object second) { } }
这显然是两个不同的方法,编辑器通过产生一个桥方法(bridge method)来调用我们希望调用的方法,类似如下:
public void setSecond(Object second) { setSecond((Date) second); }
即对于
<Date>这样的标识会有以上的桥方法替程序员正确的处理多态。
即编译器将泛型方法进行类型擦除,并调用setSecond(Object)桥方法,在桥方法内会根据类型来转换来调用正确的setSecond(Date)方法。
当然这里还有第二个问题,如果调用的不是setSecond而是getSecond,如果桥方法同样合成getSecond会出现如下情况:
Date getSecond() Object getSecond()
这样的情况对于编程人员来说通常是不允许的,即通过返回类型来标识不同的方法,但是对于虚拟机来说确实可以的。所以以上方法可以正常运行。
相关文章推荐
- java对世界各个时区(TimeZone)的通用转换处理方法(转载)
- java-注解annotation
- java-模拟tomcat服务器
- java-用HttpURLConnection发送Http请求.
- java-WEB中的监听器Lisener
- Android IPC进程间通讯机制
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- 介绍一款信息管理系统的开源框架---jeecg
- 聚类算法之kmeans算法java版本
- java实现 PageRank算法
- PropertyChangeListener简单理解
- c++11 + SDL2 + ffmpeg +OpenAL + java = Android播放器
- 插入排序
- 冒泡排序
- 堆排序
- 快速排序
- 二叉查找树