范型代码和Java虚拟机
-
关键知识:类型擦除
Java的范型是编译器层次的范型,而在Java虚拟机上并没有范型类。在程序中定义的范型类,都会被擦除类型变量,生成一个与限定类型绑定的raw type。
例如:
<T>
类型被擦除后,变为Object
类,<T entends Comparable & Serializable>
的类型被擦除后,变为第一个限定类Comparable
接口。对于多个限定类型的范型定义,编译器会插入强制类型转换。因此tagging type的接口应该放在范型类型列表的最后。
-
范型表达式
由于类型擦除,编译器在处理返回值时,会插入强制类型转换。
-
范型方法
范型类
Pair<T>
包含方法setSecond(T newValue)
。类型擦除后,虚拟机上只对应raw type方法setSecond(Object newValue)
。Pair
的派生类DateInterval extends Pair<LocalDate>
。这个类重载了setSecond(LocalDate)
。此时,在
DateInterval
中实际上有2个setSecond
方法:setSecond(LocalDate)
setSecond(Object)
而范型类在继承的时候由于类型擦除,会引起多态失效。见下面的示例:
DateInterval interval = new DateInterval(...); Pair<LocalDate> pair = interval; pair.setSecond(aDate)
而实际运行中,Java虚拟机能够处理好这种多态。这是因为编译器会自动在DateInterval类中生成一个桥函数,重载了
Pair
中的setSecond(Object)
:class DateInterval extends Pair<LocalDate> { ... public void setSecond(LocalDate second) {...} ... public void setSecond(Object second) { setSecond((LocalDate)second); } ... }
反之,
DateInterval
中的getSecond()
也生成桥方法:public LocalDate getSecond() { return (Date) super.getSecond().clone(); }
再总结一下Java范型转换:
- 虚拟机中没有范型,只有普通的类和方法
- 所有的类型参数,都被替代为限定类型(默认为Object)
- 编译器用桥方法来保持多态
- 为了保持类型安全,必要时插入强制类型转换
-
调用遗留代码
- 把范型类传入遗留代码:产生警告。
- 把遗留数据赋给范型类型:产生警告。
有警告就有警告吧,不会比没有范型的时候更糟,最大的问题就是执行时抛出一个异常。
网友评论