昆明java培训
达内昆明广州春城路

18487146383

热门课程

Java的泛型是可以擦除的

  • 时间:2016-09-30
  • 发布:昆明Java培训
  • 来源:达内新闻

昆明Java培训机构的老师知道,Java泛型(Generic)的引入加强了参数类型的安全性,减少了类型的转换,它与C++中的模板(Temeplates)比较类似,但是有一点不同的是:Java的泛型在编译器有效,在运行期被删除,也就是说所有的泛型参数类型在编译后会被清除掉,我们来看一个例子,代码如下:

1 public class Foo {

2    //arrayMethod接收数组参数,并进行重载

3    public void arrayMethod(String[] intArray) {

4

5    }

6

7    public void arrayMethod(Integer[] intArray) {

8

9    }

10    //listMethod接收泛型List参数,并进行重载

11    public void listMethod(List<String> stringList) {

12

13    }

14    public void listMethod(List<Integer> intList) {

15        

16    }

17 }

程序很简单,编写了4个方法,arrayMethod方法接收String数组和Integer数组,这是一个典型的重载,listMethod接收元素类型为String和Integer的list变量。现在的问题是,这段程序是否能编译?如果不能?问题出在什么地方?

事实上,这段程序时无法编译的,编译时报错信息如下:

这段错误的意思:简单的的说就是方法签名重复,其实就是说listMethod(List<Integer> intList)方法在编译时擦除类型后是listMethod(List<E> intList)与另一个方法重复。这就是Java泛型擦除引起的问题:在编译后所有的泛型类型都会做相应的转化。转换规则如下:

List<String>、List<Integer>、List<T>擦除后的类型为List

List<String>[]擦除后的类型为List[].

List<? extends E>、List<? super E>擦除后的类型为List<E>.

List<T extends Serializable & Cloneable >擦除后的类型为List< Serializable>.

明白了这些规则,再看如下代码:

public static void main(String[] args) {

List<String> list = new ArrayList<String>();

list.add("abc");

String str = list.get(0);

}

进过编译后的擦除处理,上面的代码和下面的程序时一致的:

public static void main(String[] args) {

List list = new ArrayList();

list.add("abc");

String str = (String) list.get(0);

}

Java编译后字节码中已经没有泛型的任何信息了,也就是说一个泛型类和一个普通类在经过编译后都指向了同一字节码,比如Foo<T>类,经过编译后将只有一份Foo.class类,不管是Foo<String>还是Foo<Integer>引用的都是同一字节码。Java之所以如此处理,有两个原因:

避免JVM的大换血。C++泛型生命期延续到了运行期,而Java是在编译期擦除掉的,我们想想,如果JVM也把泛型类型延续到运行期,那么JVM就需要进行大量的重构工作了。

版本兼容:在编译期擦除可以更好的支持原生类型(Raw Type),在Java1.5或1.6...平台上,即使声明一个List这样的原生类型也是可以正常编译通过的,只是会产生警告信息而已。

明白了Java泛型是类型擦除的,我们就可以解释类似如下的问题了:

泛型的class对象是相同的:每个类都有一个class属性,泛型化不会改变class属性的返回值,例如:

public static void main(String[] args) {

List<String> list = new ArrayList<String>();

List<Integer> list2 = new ArrayList<Integer>();

System.out.println(list.getClass()==list2.getClass());

}

以上代码返回true,原因很简单,List<String>和List<Integer>擦除后的类型都是List,没有任何区别。

2.泛型数组初始化时不能声明泛型,如下代码编译时通不过:

List<String>[] listArray = new List<String>[];

原因很简单,可以声明一个带有泛型参数的数组,但不能初始化该数组,因为执行了类型擦除操作,List<Object>[]与List<String>[]就是同一回事了,编译器拒绝如此声明。

3.instanceof不允许存在泛型参数

以下代码不能通过编译,原因一样,泛型类型被擦除了:

List<String> list = new ArrayList<String>();

System.out.println(list instanceof List<String>);

了解详情请登陆昆明达内Java培训官网(km.Java.tedu.cn)!

上一篇:测试一下StringBuffer和StringBuilder及字面常量拼接三种字符串的效率
下一篇:不能初始化泛型参数和数组

电脑编程学什么专业好?java好吗?【达内java培训】

上java培训有用吗?怎么衡量?【达内培训】

昆明java培训机构怎么选?昆明达内java培训怎么样?

学Java自学还是达内培训机构好?

选择城市和中心
贵州省

广西省

海南省

台湾