ArrayStoreException

最近看到一段JDK中ArrayList類中的源碼,其中一段註釋吸引了我的眼球,爲了弄清其含義,特意找了一些資料,寫了一點測試代碼。源代碼如下:

/**
 * Constructs a list containing the elements of the specified
 * collection, in the order they are returned by the collection's
 * iterator.
 *
 * @param c the collection whose elements are to be placed into this list
 * @throws NullPointerException if the specified collection is null
 */
public ArrayList(Collection<? extends E> c) {
    elementData = c.toArray();
    if ((size = elementData.length) != 0) {
        // c.toArray might (incorrectly) not return Object[] (see 6260652)
        if (elementData.getClass() != Object[].class)
            elementData = Arrays.copyOf(elementData, size, Object[].class);
    } else {
        // replace with empty array.
        this.elementData = EMPTY_ELEMENTDATA;
    }
}
爲了弄清楚// c.toArray might (incorrectly) not return Object[] (see 6260652)這句註釋的意義,特意查了一下官方的bug文檔,Bug ID:JDK-6260652,地址如下

http://bugs.java.com/bugdatabase/view_bug.do?bug_id=6260652


官方文檔上有這樣一段描述


A DESCRIPTION OF THE PROBLEM :
The Collection documentation claims that

    collection.toArray()

is "identical in function" to

    collection.toArray(new Object[0]);

However, the implementation of Arrays.asList does not follow this: If created with an array of a subtype (e.g. String[]), its toArray() will return an array of the same type (because it use clone()) instead of an Object[].

If one later tries to store non-Strings (or whatever) in that array, an ArrayStoreException is thrown.

用我稀爛的英語翻譯了一下就是:

該問題的描述
Collection文檔上是這樣聲稱的
toArray(new Object[0])函數和toArray()是相同的。
然而,Arrays.asList的實現並不遵循這一點:如果用子類創建了一個數組,比方說String[]數組,它的toArray()方法將返回一個相同類型的數組(因爲使用了clone()方法)而不是一個Object[]數組。

如果後來試圖存儲一個非String類型(或者其他類型)的數據到這個數組中,就會拋出ArrayStoreException 。


爲此我特意翻看了JDK中Collection接口的API文檔,確實有那麼一句描述



通過API文檔發現這兩個方法並不是完全一致

Object[] toArray()
<T> T[] toArray(T[] a)
一個返回的是確定的Object[]數組,另一個是泛型,根據運行時的類型來確定。

結合JDK的API文檔和官方的bug文檔,基本可以確定就返回類型導致拋出ArrayStoreException。


接下來寫了2個測試的例子:

public static void main(String[] args) {
    String[] array = {"a","b"};
    Object[] o = array;
    System.out.println(o.getClass());
    o[0] = new Object();
}
運行結果:

class [Ljava.lang.String;
Exception in thread "main" java.lang.ArrayStoreException: java.lang.Object

在第一個例子中將String[]類型的數組向上轉型成爲Object[]數組,而真正在運行時,打印出來該數組的實際類型依舊是String[]數組,之後向該數組中插入一個Object類型的元素時,拋出異常。


public static void main(String[] args) {
    List<String> list = Arrays.asList("a","b");
    System.out.println(list.getClass());
    Object[] o = list.toArray();
    System.out.println(o.getClass());
    o[0] = new Object();
}
運行結果:

class java.util.Arrays$ArrayList
class [Ljava.lang.String;
Exception in thread "main" java.lang.ArrayStoreException: java.lang.Object

在第二個例子中聲明瞭一個List<String>的集合,運行時得到的是Arrays的內部類ArrayList類型,通過toArray()方法後,實際得到的是String[]數組,也不是Object[]數組,之後插入元素的時候拋出異常。


正因爲運行時可能會出現ArrayStoreException,ArrayList類中判斷了數組類型不是Object類型時,新建了一個Object[]數組,已保證不會出現異常

// c.toArray might (incorrectly) not return Object[] (see 6260652)
if (elementData.getClass() != Object[].class)
    elementData = Arrays.copyOf(elementData, size, Object[].class);

發佈了45 篇原創文章 · 獲贊 65 · 訪問量 9萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章