java泛型问题分析
转载:https://baijiahao.baidu.com/s?id=1590433913335343847&wfr=spider&for=pc
Java泛型(Generic) 的引入加强了参数类型的安全性,减少了类型的转换,它与C++中的模板(Temeplates) 比较类似,但是有一点不同的是:Java的泛型在编译器有效,在运行期被删除,也就是说所有的泛型参数类型在编译后会被清除掉,我们来看一个例子,代码如下:
程序很简单,编写了4个方法,arrayMethod方法接收String数组和Integer数组,这是一个典型的重载,listMethod接收元素类型为String和Integer的list变量。现在的问题是,这段程序是否能编译?如果不能?问题出在什么地方?
事实上,这段程序时无法编译的,编译时报错信息如下:
这段错误的意思:简单的的说就是方法签名重复,其实就是说listMethod(List intList)方法在编译时擦除类型后是listMethod(List intList)与另一个方法重复。这就是Java泛型擦除引起的问题:在编译后所有的泛型类型都会做相应的转化。转换规则如下:
List、List、List擦除后的类型为List
List[] 擦除后的类型为List[].
List 、List 擦除后的类型为List.
List擦除后的类型为List.
明白了这些规则,再看如下代码:
经过编译后的擦除处理,上面的代码和下面的程序时一致的:
Java编译后字节码中已经没有泛型的任何信息了,也就是说一个泛型类和一个普通类在经过编译后都指向了同一字节码,比如Foo类,经过编译后将只有一份Foo.class类,不管是Foo还是Foo引用的都是同一字节码。Java之所以如此处理,有两个原因:
避免JVM的大换血。C++泛型生命期延续到了运行期,而Java是在编译期擦除掉的,我们想想,如果JVM也把泛型类型延续到运行期,那么JVM就需要进行大量的重构工作了。
版本兼容:在编译期擦除可以更好的支持原生类型(Raw Type),在Java1.5或1.6...平台上,即使声明一个List这样的原生类型也是可以正常编译通过的,只是会产生警告信息而已。
明白了Java泛型是类型擦除的,我们就可以解释类似如下的问题了:
泛型的class对象是相同的:每个类都有一个class属性,泛型化不会改变class属性的返回值,例如:
以上代码返回true,原因很简单,List和List擦除后的类型都是List,没有任何区别。
2.泛型数组初始化时不能声明泛型,如下代码编译时通不过:
原因很简单,可以声明一个带有泛型参数的数组,但不能初始化该数组,因为执行了类型擦除操作,List[]与List[] 就是同一回事了,编译器拒绝如此声明。
3.instanceof不允许存在泛型参数(不是很理解,有大神可以指点下)
以下代码不能通过编译,原因一样,泛型类型被擦除了: