您的位置:首页 > 编程语言 > Java开发

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()


这样的情况对于编程人员来说通常是不允许的,即通过返回类型来标识不同的方法,但是对于虚拟机来说确实可以的。所以以上方法可以正常运行。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息