1. 為了方面按列作外循環,想把ArrayList構造成一個二維數組,如下:
......
ArrayList result=GetResult();
int n=result.size();
String[][] myArray=new String[n][]; //定義二維數組
for (int i=0;i<n;i++) //構造二維數組
{
ArrayList tempArray= (ArrayList)result.get(i);
myArray[i]=(String[])tempArray.toArray();
}
......
程序可以編譯通過。
但在運行到myArray[i]=(String[])tempArray.toArray()時,出現java.lang.ClassCastException的錯誤,很奇怪。
花了一晚上時間,查了N多資料,總算搞定了?,F把問題記錄下來,以備參考。
2. 此事從頭說起?! ?/p>
ArrayList類擴展AbstractList并執行List接口。ArrayList支持可隨需要而增長的動態數組。
ArrayList有如下的構造函數:
ArrayList( )
ArrayList(Collection c)
ArrayList(int capacity)
如果調用new ArrayList()構造時,其默認的capacity(初始容量)為10。
參見ArrayList源碼,其中是這樣定義的:
public ArrayList() {
this(10);
}
默認初始化內部數組大小為10。為什么是10?不知道??赡躍UN覺得這樣比較爽吧。
程序編譯后執行ArrayList.toArray(),把ArrayList轉化為數組時,該數組大小仍為capacity(為10)。
當裝入的數據和capacity值不等時(小于capacity),比如只裝入了5個數據,數組中后面的(capacity - size)個對象將置為null,此時當數組強制類型轉換時,容易出現一些問題,如java.lang.ClassCastException異常等。
解決辦法是:在用ArrayList轉化為數組裝數據后,使用trimToSize()重新設置數組的真實大小。
3. 本例修改后的代碼修如下,可順利運行:
for (int i=0;i<n;i++) //構造二維數組
{
ArrayList tempArray= (ArrayList)result.get(i);
myArray[i]=(String[])tempArray.toArray(new String[0]); //注意此處的寫法
}
看看下面這些也許就明白了--
ArrayList.toArray()之一:
public Object[] toArray() {
Object[] result = new Object[size];
System.arraycopy(elementData, 0, result, 0, size);
return result;
}
返回ArrayList元素的一個數組,注意這里雖然生成了一個新的數組,但是數組元素和集合中的元素是共享的,Collection接口中說這個是安全的,這是不嚴格的。
下面的例子演示了這個效果。
ArrayList al=new ArrayList();
al.add(new StringBuffer("hello"));
Object[] a=al.toArray();
StringBuffer sb=(StringBuffer)a[0];
sb.append("changed"); //改變數組元素同樣也改變了原來的ArrayList中的元素
System.out.println(al.get(0));
這里不要用String來代替StringBuffer,因為String是常量。
ArrayList.toArray()之二:
public Object[] toArray(Object a[]) {
if (a.length < size)
a = (Object[])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;
}
這個方法有可能不需要生成新的數組,注意到如果數組a容量過大,只在size處設置為null。
如果這個數組a足夠大,就會把數據全放進去,返回的數組也是指向這個數組,(數組多余的空間存儲的是null對象);要是不夠大,就申請一個跟參數同樣類型的數組,把值放進去,然后返回。
4. 網上的資料一:
public String[] getPlatformIDList()
{
Vector result = new Vector();
try
{
Statement stmt = conn.createStatement();
String sql = "SELECT PlatformID FROM Platform";
rs = stmt.executeQuery(sql);
while(rs.next())
{
result.add(rs.getString(1));
}
if (result.size() > 0)
{
String[] str = (String[]) result.toArray(); // 出現ClassCastException
return str;
}
else
return null;
}
catch(Exception e)
{
System.err.println(e);
return null;
}
finally
{
try
{
rs.close();
conn.close();
}
catch(Exception e2)
{}
}
}
程序運行后,發現不能將Vector類經過toArray()方法得到的Object[]直接轉換成String[]。
找到用另一個帶有參數的 toArray(T[] a)方法才可以。
將該語句改為:
String[] str = (String[]) result.toArray(new String[1]);即告訴Vector,我要得到的數組的類型。
回想一下,應該是java中的強制類型轉換只是針對單個對象的,想要偷懶,將整個數組轉換成另外一種類型的數組是不行的。
5. 網上的資料二:
正確使用List.toArray()--
在程序中,往往得到一個List,程序要求對應賦值給一個array,可以這樣寫程序:
Long [] l = new Long[list.size()];
for(int i=0;i<list.size();i++)
l[i] = (Long) list.get(i);
要寫這些code,似乎比較繁瑣,其實List提供了toArray()的方法。
但是要使用不好,就會有ClassCastExceptiony異常。究竟這個是如何產生的,且看代碼:
List list = new ArrayList();
list.add(new Long(1));list.add(new Long(2));
list.add(new Long(3));list.add(new Long(4));
Long[] l = (Long[])list.toArray();
for(int i=0; i<l.length; i++)
System.out.println(l[i].longValue());
紅色代碼會拋java.lang.ClassCastException。
當然,為了讀出值來,你可以這樣code:
Object [] a = list.toArray();
for(int i=0;i<a.length;i++)
System.out.println(((Long)a[i]).longValue());
但是讓數組丟失了類型信息,這個不是我們想要得。
toArray()正確使用方式如下:
1) Long[] l = new Long[<total size>];
list.toArray(l);
2) Long[] l = (Long []) list.toArray(new Long[0]);
3) Long [] a = new Long[<total size>];
Long [] l = (Long []) list.toArray(a);
6. 總結補充:
java sdk doc 上講:
public Object[] toArray(Object[] a)
a--the array into which the elements of this list are to be stored, if it is big enough; otherwise, a new array of the same runtime type is allocated for this purpose.
如果這個數組a足夠大,就會把數據全放進去,返回的數組也是指向這個數組,(數組多余的空間存儲的是null對象);要是不夠大,就申請一個跟參數同樣類型的數組,把值放進去,然后返回。
需要注意的是:你要是傳入的參數為9個大小,而list里面有5個object,那么其他的四個很可能是null , 使用的時候要特別注意。
7. 完畢。