天天看點

Java中List轉換為Array

今天寫代碼遇到一個奇怪的問題,具體代碼不貼出了,寫一個簡化的版本。如下:

ArrayList<String> list=new ArrayList<String>();
 String strings[]=(String [])list.toArray();      

這樣寫代碼個人覺得應該沒什麼問題,編譯也沒有問題。可是具體運作的時候報異常,如下:Exception in thread "main" java.lang.ClassCastException: [Ljava.lang.Object;

但是這麼寫是沒有問題的:

ArrayList<String> list=new ArrayList<String>();
           String strings[]=new String[list.size()];
           for(int i=0,j=list.size();i<j;i++){
               strings[i]=list.get(i);
           }      

對于這個現象我們可以這麼解釋:Java中允許向上和向下轉型,但是這個轉型是否成功是根據Java虛拟機中這個對象的類型來實作的。Java虛拟機中儲存了每個對象的類型。而數組也是一個對象。數組的類型是[Ljava.lang.Object。把[Ljava.lang.Object轉換成[Ljava.lang.String是顯然不可能的事情,因為這裡是一個向下轉型,而虛拟機隻儲存了這是一個Object的數組,不能保證數組中的元素是String的,是以這個轉型不能成功。數組裡面的元素隻是元素的引用,不是存儲的具體元素,是以數組中元素的類型還是儲存在Java虛拟機中的。

根據上面的解釋,我們可以把這個問題歸納到下面這個模型:

Object objs[]=new Object[10];

String strs[]=(String[])objs;

這樣子和剛才上面編譯錯誤是一樣的。如果我們修改一下這個代碼,如下:

String strs[]=new String[10];

Object objs[]=strs;

這樣子就可以編譯通過了。是以這個問題我們可以歸結為一個Java轉型規則的問題。下面談一下Java數組對範型的支援問題。

JDK5中已經有了對範型的支援,這樣可以保證在集合和Map中的資料類型的安全,可是,List的toArray方法傳回的竟然是Object []讓人很迷惑。個人感覺應該可以根據範型,直接傳回相應的T []。仔細看了一下JDK的源碼發現List轉化為array有兩個方法:

public Object[] toArray();      

這個方法把List中的全部元素傳回一個相同大小的數組,數組中的所有元素都為Object類型。

public <T> T[] toArray(T[] a);

這個方法把List中的全部元素傳回一個相同大小的數組,數組中的所有元素都為T類型。

List如此設計是因為Java編譯器不允許我們new範型數組。也就是說你不能這麼定義一個數組:

T arr=new T[size];

但是你卻可以用T[]來表示數組,而且可以把數組強制轉化為T[]。比如List中的public <T> T[] toArray(T[] a)是這麼實作的:

public <T> T[] toArray(T[] a) {
           if (a.length < size)
               a = (T[])java.lang.reflect.Array.
     newInstance(a.getClass().getComponentType(), size);
 System.arraycopy(elementData, 0, a, 0, size);
           if (a.length > size)
               a[size] = null;
           return a;
       }      
ArrayList<String> list=new ArrayList<String>();
String[] strings = new String[list.size()];
list.toArray(strings);      
String[] s = {"a","b","c"}; 
 List list = java.util.Arrays.asList(s);