今天寫代碼遇到一個奇怪的問題具體代碼不貼出了出一個簡化的版本例如下面代碼
ArrayList<String> list=new ArrayList<String>();
String strings[]=(String [])listtoArray();
這樣寫代碼個人覺得應該沒什麼問題編譯也沒有問題可是具體運行的時候報異常如下Exception in thread main javalangClassCastException: [LjavalangObject;
但是你這麼寫是沒有問題的
ArrayList<String> list=new ArrayList<String>();
String strings[]=new String[listsize()];
for(int i=j=listsize();i<j;i++){ strings[i]=listget(i);
}
對於這個現象我們可以這麼解釋Java中允許向上和向下轉型但是這個轉型是否成功是根據Java虛擬機中這個對象的類型來實現的Java虛擬機中保存了每個對象的類型而數組也是一個對象數組的類型是[LjavalangObject把[LjavalangObject轉換成[LjavalangString是顯然不可能的事情因為在這個是一個向下轉型而虛擬機只保存了這是一個Object的數組不能保證數組中的元素是String的所以這個轉型不能成功數組裡面的元素只是元素的引用不是存儲的具體元素所以數組中元素的類型還是保存在Java虛擬機中的
根據上面的解釋我們可以把這個問題歸納到下面這個模型
Object objs[]=new Object[];
String strs[]=(String[])objs;
這樣子和剛才上面編譯錯誤是一樣的如果我們把修改一下這個代碼如下
String strs[]=new String[];
Object objs[]=strs;
這樣子就可以編譯通過了所以這個問題我們可以歸結為一個Java轉型規則的一個問題下面談一下Java數組對范型的支持問題
JDK中已經有了對范型的支持這樣可以保證在集合和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 (alength < size) a = (T[])javalangreflectArray newInstance(agetClass()getComponentType() size);
Systemarraycopy(elementData a size);
if (alength > size)
a[size] = null;
return a;
}
從上面代碼中可以看到你必須通過反射來創建這個數組因為你不知道這個數組的類型agetClass()getComponentType()方法是取得一個數組元素的類型
From:http://tw.wingwit.com/Article/program/Java/hx/201311/25524.html