再回首Java第二十七天

泛型与数组

JDK1.5还有一个很重要的设计原则:如果一段代码在编译时系统没有产生:”unchecked未经检测的转换“,则程序在运行时不会引发”ClassCastException“异常。正是基于这个原因,所以数组元素的类型不能包含类型变量或类型形参,除非是无上限的类型通配符。但可以声明这样的数组,即使声明元素类型包含类型变量或类型形参的数组。也就是说:只能声明List<String>[]数组,但不能创建ArrayList<String>[10]这样的数组对象

假设Java能支持创建ArrayList<String>[10]这样的数组对象,则有如下程序

 //下面代码实际上是不允许的

List<String>[]  lsa=new ArrayList<String>[10];

//强制类型转化为一个Object数组

Object[] oa=(Object[])lsa;

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

li.add(new Integer(3));

//将List<Integer>对象作为oa的第一个元素

//下面代码没有任何警告

oa[1]=li;

//下面代码也不会有任何警告,但是会引起ClassCastException异常

String s=lsa[1].get(0);

如果能够创建ArrayList<String>[10]这样的数组,经过中间系列的程序运行,势必在代码最后一行引起异常,这就违背Java泛型的设计原则

如果将程序该成如下形式

//下面代码编译时有 “[unchecked]未经检查的转换”警告

List<String>[] lsa=new ArrayList[10];

Object[] oa=(Object[]) lsa;

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

li.add(new Integer(3));

oa[1]=li;

//下面代码将一起ClassCastException异常

String s=lsa[1].get(0);

上面代码:声明List<String>[]类型的数组变量时允许的;但不允许创建List<String>[]类型的对象,所以创建了一个ArrayList[10]的数组对象,这是允许的。只是把ArrayList<10>对象赋值给List<String>[]变量时会有编译警告:未经检查的转换,即编译器不保证这段代码的类型安全的。所以后面代码会引发ClassCastException异常,但因为编译器 已经提出了警告,所以完全有可能发生这种异常

Java运行创建无上限的通配符泛型数组,例如new ArrayList<?>[10],在这种情况下程序不得不进行强制类型转换,如下代码所示

List<?>[] lsa=new ArrayList<?>[10];

Object[] oa=(Object[]) lsa;

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

li.add(new Integer(3));

oa[1]=li;

//下面代码将一起ClassCastException异常

String s=lsa[1].get(0);

编译上面代码不会引起任何警告,当程序运行到最后引发ClassCastException异常,因为程序将lsa的第一个元素的第一个集合元素赋值给String类型的变量,所以程序应该自己通过instanceof运算符来保证它的数据类型

List<?>[] lsa=new ArrayList<?>[10];

Object[] oa=(Object[]) lsa;

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

li.add(new Integer(3));

oa[1]=li;

Object target=lsa[1].get(0);

if(target instanceof String){

String s=(String)target;

}

与此类似的是:创建元素类型是类型变量的数组对象也将导致编译错误。如下面代码所示:

<T> T[] makeArray(Collection<T> coll){

//下面代码将导致编译错误

return new T[coll.size()];

}

因为类型变量在运行时并不存在,所以编译器无法确定实际类型是什么

 

posted @ 2016-05-16 00:12  刀口一人  阅读(115)  评论(0编辑  收藏  举报