1700446955
1700446956
another method in type Foo
1700446957
1700446958
此错误的意思是说listMethod(List<Integer>)方法在编译时擦除类型后的方法是listMethod(List<E>),它与另外一个方法重复,通俗地说就是方法签名重复。这就是Java泛型擦除引起的问题:在编译后所有的泛型类型都会做相应的转化。转换规则如下:
1700446959
1700446960
List<String>、List<Integer>、List<T>擦除后的类型为List。
1700446961
1700446962
List<String>[]擦除后的类型为List[]。
1700446963
1700446964
List<?extends E>、List<?super E>擦除后的类型为List<E>。
1700446965
1700446966
List<T extends Serializable&Cloneable>擦除后为List<Serializable>。
1700446967
1700446968
明白了这些擦除规则,再看如下代码:
1700446969
1700446970
public static void main(String[]args){
1700446971
1700446972
List<String>list=new ArrayList<String>();
1700446973
1700446974
list.add(“abc”);
1700446975
1700446976
String str=list.get(0);
1700446977
1700446978
}
1700446979
1700446980
经过编译器的擦除处理后,上面的代码与下面的程序是一致的:
1700446981
1700446982
public static void main(String[]args){
1700446983
1700446984
List list=new ArrayList();
1700446985
1700446986
list.add(“abc”);
1700446987
1700446988
String str=(String)list.get(0);
1700446989
1700446990
}
1700446991
1700446992
Java编译后的字节码中已经没有泛型的任何信息了,也就是说一个泛型类和一个普通类在经过编译后都指向了同一字节码,比如Foo<T>类,经过编译后将只有一份Foo.class类,不管是Foo<String>还是Foo<Integer>引用的都是同一字节码。Java之所以如此处理,有两个原因:
1700446993
1700446994
避免JVM的大换血。C++的泛型生命期延续到了运行期,而Java是在编译器擦除掉的,我们想想,如果JVM也把泛型类型延续到运行期,那么JVM就需要进行大量的重构工作了。
1700446995
1700446996
版本兼容。在编译期擦除可以更好地支持原生类型(Raw Type),在Java 1.5或1.6平台上,即使声明一个List这样的原生类型也是可以正常编译通过的,只是会产生警告信息而已。
1700446997
1700446998
明白了Java的泛型是类型擦除的,我们就可以解释类似如下的问题了:
1700446999
1700447000
(1)泛型的class对象是相同的
1700447001
1700447002
每个类都有一个class属性,泛型化不会改变class属性的返回值,例如:
1700447003
1700447004
public static void main(String[]args){
[
上一页 ]
[ :1.700446955e+09 ]
[
下一页 ]