2012-09-11 41 views
30
Object[] o = "a;b;c".split(";"); 
o[0] = 42; 

拋出與ArrayStoreException信息處理

java.lang.ArrayStoreException: java.lang.Integer 

String[] s = "a;b;c".split(";"); 
Object[] o = new Object[s.length]; 
for (int i = 0; i < s.length; i++) { 
    o[i] = s[i]; 
} 
o[0] = 42; 

沒有。

是否有任何其他的方式來處理該異常,而無需創建一個臨時String[]陣列?

+4

Object [] o =「a; b; c」.split(「;」); o [0] = 42;這裏你要創建一個字符串數組,而Object [] o = new Object [s.length];是一個對象數組。 – Satya

回答

53

在Java陣列也是對象

您可以將子類型的對象放入超類型變量的變量中。例如,您可以將String對象放入Object變量中。

不幸的是,Java中的數組定義被破壞了。 String[]被認爲是Object[]的子類型,但這是錯誤!爲了瞭解「協變和逆變」更詳細的解釋,但本質上它是:A型應該算是另一種類型的子類型只有在滿足亞型所有義務的超類型的。這意味着,如果你得到的是一個子類型對象而不是一個超類型對象,那麼你就不應該期待與超類型合約相矛盾的行爲。

問題是,String[]僅支持Object[]合同一個一部分。例如,您可以從Object[]讀取Object的值。而且你還可以閱讀Object值(這恰好是String對象)從String[]。到現在爲止還挺好。問題在於合同的其他部分。您可以將任何Object納入Object[]。但是你不能把任何Object納入String[]。因此,String[]不應被視爲Object[]的子類型,但Java規範說明它是。因此我們有這樣的後果。

(請注意,類似的情況,以與一般類又出現了,不過這次它被正確地解決List<String>List<Object>亞型;如果你想擁有這些共同的超類型,你需要List<?>,它是隻讀的。這也是它應該如何與陣列;但事實並非如此。並且由於向後兼容性,現在要更改它爲時已晚。)

在第一個示例中,String.split函數會創建一個String[]對象。您可以將它放入一個Object[]變量,但對象仍爲String[]。這就是它拒絕Integer值的原因。您必須創建一個新的Objects[]數組,並複製這些值。您可以使用System.arraycopy函數來複制數據,但無法避免創建新陣列。

+0

http://www.angelikalanger.com/GenericsFAQ/FAQSections/ParameterizedTypes.html#FAQ102 –

6

沒有,有沒有辦法避免複製數組split回報。

的數組split回報實際上是一個String[],和Java允許您指定,要Object[]類型的變量。但它仍然是一個String[],因此當您嘗試在其中存儲除String之外的其他內容時,您將獲得一個ArrayStoreException

有關背景信息,請參閱4.10.3. Subtyping among Array Types在Java語言規範。

0

當然還有其他的選擇,比如你實現你自己的split方法,它直接返回一個Object數組。我不確定究竟是什麼使臨時String數組困擾你?

順便說一句,你可以使用幾行System.arrayCopy,而不是實施自己的循環複製的數組元素縮短代碼:

System.arrayCopy(s, 0, o, 0, s.length); 
-1

如果它沒有必要用一個「分裂」 ..然後你可以避免複製...