Java Code
List是原生类型,那它可不可以转成List<String> List<?> List<? Extends T> 等等的类型,那么这些类型之间可以怎样转来转去呢,运行过程中却有可能出现什么样的异常,我今天就大胆提出一些自己的观点,欢迎指正
引用跟对象是两回事,引用(如List<String>)负责类型检测,而new 出来的对象跟这个泛型没关系,对象不检查类型。
我下面的讲述也会围绕这点展开
List
new
java是支持、且希望你为那些泛型类的对象添加一个有泛型的引用来对这个对象进行更严格的操作的。
因而,原List引用所指的对象可以由List<Type> 、List<? ectends Type> 、List<? super Type> 指向,
List转List<String>
public class TestList
{
public static void main( String [] args)
{
List list= new ArrayList();
List< String > list1= new ArrayList< String >();
list.add( "回到家还是" );
list.add( 123 );
list.add( 12 . 34 );
list1=list; //warnings 类型安全:类型 List 的表达式需要进行未经检查的转换以符合 List<String>
System.out.println(list1.get( 1 )); //正常输出"回到家还是"
System.out.println(list1.get( 0 )); //出现异常ClassCastException
System.out.println(list1); //此操作不会出现异常,因为toString不涉及泛型
}
}
我应该说的准确一点, list1=list;这一步操作不叫转成,应该叫做:用 List<String> list1的这个引用去操作 List list所指的对象new ArrayList();
解析一下:对象跟应用是两回事,在泛型中类型检测是由引用来进行的的(不懂的朋友请参考这篇文章)
用 List<String> list1 的这个引用去操作 List list所指的对象new ArrayList()是可以的,
首先、在 List list=new ArrayList(); 这一步中 list所指对象里面存的是Object
其次、 List<String> list1=new ArrayList<String>(); list1=list; 用list1这个引用指向 list所指的那个对
象 newnew ArrayList()就只能执行更严格的操作,只能往里面存放String类型的数据,所以编译
器允许你这样做。但是很有可能在进行 list1=list 前 new ArrayList()这个对象已经放进了其他类型的数据(8 到10
行),因而在在取出非String类型数据的时候,会出现转换异常
List转List<? extends Number>
Java Code
public class TestList
{
public static void main( String[] args)
{
List list= new ArrayList();
list.add( 123);
list.add( 33. 7);
list.add( "cc");
List<? extends Number> list1=list;
Number b=list1.get( 2); //运行时出错 ClassCastException
}
}
道理跟上面的一样因为 List<? extends List<? extends Number> list1引用能对
的 new ArrayList() 的对象执行更严格的操作,所以编译允许这样的操作通过。但是有可能 list1=list;之前的就已经放
了其他非Number的数据,所以在取出数据的时候可能发生ClassCastException异常。
List转List<? super Integer>
Java Code
public
class TestList
{
public
static
void main(
String[] args)
{
List list=
new ArrayList();
list.add(
12.
34);
list.add(
"每一天");
List<?
super Integer> listSup=list; //
listSup.add(
123);
for (
int i =
0; i < list.size(); i++)
{
Object obj = listSup.get(i);
System.out.println(obj);
}
}
}
这种情况跟上面有点特别 listSup = list 之前无论 list所指对象里面放了什么类型的数据,在listSup 指向后,仍能正常的取出数据而不出现ClassCastExcption异常,因为 List<? super Integer> 引用取出的都是Object对象。
List<? extends Type> & List<? super Type>
对于泛型对象(List容器),java希望没有通配符的尽量要有通配符,所以你可以看到上面的List可以转成List<Type> 、List<? ectends Type> 、List<? super Type>等
等,但是对于已经有泛型的,他就要求准确,只能小的往大的转
如
extends Number> = List<Integer>
List<? extends Number> = List<? extends Integer>
List<? super Integer> = List<? super Number>
//语法肯定不对,只是做个比喻
List<? extends Object> 转 List<String>
Java Code
public class TestList
{
public static void main( String[] args)
{
List<? extends Object> list_Exends_Object;
List<? extends String> list_Exends_String;
List< String> list_String = new ArrayList< String>();
list_String=list_Exends_String; //error
//类型不匹配:不能从 List<capture#1-of ? extends String> 转换为 List<String>
list_String=list_Exends_ Object; //error
}
}
List<? extends Object> 所指的对象可能是专门放String 的List(List<String>)、专门放放Object的List(List<Object>)、、、都有可能。如果 list_String=list_Exends_Object; 这个操作成功,不就说你可以用
List<String> list_String 这个引用去操纵一个可能是 Object、String、Number等的对象,List<String> list_String 这个
引用的泛型就表明只能往所指的对象Set 、Get String对象,总不可能往Number对象中放String对象吧。
如果 List<String>List_String = list_Exends_Object;成功,不就意味着可以往List<? extends Object> list_Exends_Object这个原来所指的对象放入String,
即:
Java Code
String> list= new ArrayList< String>();
List<? extends Object> list_Exend_Object=list;
List< String> list_String = ist_Exend_Object; // error
因为新的引用是List<String>啊,但是原来的引用 List<? extends Object> list_Exends_Object所指向的具体对象是Number、还是String、或其他的,编译器根本不知
道,因而它不会让你一错再错。
List<? extends Number> 转 List<? extends Integer>
public class TestList
{
public static void main( String[] args)
{
List<? extends Number> listN=null;
List<? extends Integer> listI=null;
listN=listI;
//listI=listN; 编译不通过,类型不匹配
}
}
在这里 引用 List<? extendsList<? extends Integer> listI 的 对象,但是反过来却不可以。
理由也很简单如果引用 List<? extends List<? extends Number> listN所指的对象,就有可能出错
public class TestList
{
public static void main( String[] args)
{
List<? extends Number> listN= new ArrayList<Number>();
//listN 指向的是一个 只允许放 Number的 ArrayList
List<? extends Integer> listI=null;
listI=listN; //实际是错误的,在这里假设可行
listI.get( 0);
//返回的将是一个Integr
//原来的ArrayList放的是Number
//Number不一定可以转换成Integer
}
}
List<? extends Type> 转 List<? super Type>
List<? extends AnyType> 引用是不能指向 List<? super AnyType> 所指的对象的,反过来也一样,因为 ? super Type 与 ? extends Type 之间总是会有交集的,不存
在谁包含谁的关系。
Java Code
public class TestList
{
public static void main( String[] args)
{
List<? extends Number> listExt=null;
List<? super Integer> listSup=null;
//listExt=listSup;
//listSup=listExt;
}
}
List<? >等价于 List<? extends Object>
List<? >的情况跟List<? extends Object>一样,以后我会另写文章论述
这是我的一己之见,上面内容纯粹是个人的猜测,难免会有错,请各位指正。