List是原生类型,那它可不可以转成List<String> List<?> List<? Extends T> 等等的类型,那么这些类型之间可以怎样转来转去呢,运行过程中却有可能出现什么样的异常,我今天就大胆提出一些自己的观点,欢迎指正
List
1
|
List list=
new ArrayList();
|
List转List<String>
1
2
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
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所指的那个对
象 new ArrayList()后,这样 new ArrayList()就只能执行更严格的操作,只能往里面存放String类型的数据,所以编译
器允许你这样做。但是很有可能在进行 list1=list 前 new ArrayList()这个对象已经放进了其他类型的数据(8 到10
行),因而在在取出非String类型数据的时候,会出现转换异常
List转List<? extends Number>
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
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 } } |
的 new ArrayList() 的对象执行更严格的操作,所以编译允许这样的操作通过。但是有可能 list1=list;之前的就已经放
了其他非Number的数据,所以在取出数据的时候可能发生ClassCastException异常。
List转List<? super Integer>
Java Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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对象。
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
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); } } } |
List<? extends Type> & List<? super Type>
1
2 3 4 |
List<?
extends Number> = List<Integer>
List<? extends Number> = List<? extends Integer> List<? super Integer> = List<? super Number> //语法肯定不对,只是做个比喻 |
List<? extends Object> 转 List<String>
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
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<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,
即:
1
2 3 4 |
List<
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>
1
2 3 4 5 6 7 8 9 10 11 12 |
public
class TestList
{ public static void main( String[] args) { List<? extends Number> listN=null; List<? extends Integer> listI=null; listN=listI; //listI=listN; 编译不通过,类型不匹配 } } |
理由也很简单如果引用 List<? extends Integer> listI 可以指向 List<? extends Number> listN所指的对象,就有可能出错
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
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 之间总是会有交集的,不存
在谁包含谁的关系。
1
2 3 4 5 6 7 8 9 10 11 12 13 |
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>一样,以后我会另写文章论述