2012-11-28 39 views

回答

2

使用通用類型的數組(如ArrayList<T>)是一種下地獄。下面這行甚至不編譯:

ArrayList<Record<T>>[] values = new ArrayList<Record<T>>[SIZE_ARRAY]; 

編譯器會發出這樣的錯誤:

Cannot create a generic array of ArrayList<Record<T>> 

唯一明智的解決方案是創建一個列表的列表:

// create matrix 
ArrayList<ArrayList<Record<T>>> matrix = new ArrayList<ArrayList<Record<T>>>(); 

// add 3 rows: 
for (int i = 0; i < 3; i++) { 
    ArrayList<Record<T>> row = new ArrayList<Record<T>>(); 
    matrix.add(row); 

    // add 4 elements to each row 
    for (int j = 0; j < 4; j++) { 
     Record<T> record = ... // get the record 
     row.add(record); 
    } 
} 

現在您可以訪問[2] [3](最後一行的最後一個元素)處的元素:

Record<T> record = matrix.get(2).get(3); 
+0

+1。感謝您提出我的問題。 – dreamcrash

+0

不客氣:) – Natix

+0

「唯一明智的解決方案是創建一個列表清單:」不,它不是。完全可以創建一個ArrayList數組。 – newacct

0

只要做到:

ArrayList<Record<T>>[] values = (ArrayList<Record<T>>[])new ArrayList<?>[SIZE_ARRAY]; 

將會有一個未經檢查的投警告,你可以忽略基本。

數組創建參數化類型被禁止的真正原因是一種深奧的。 Java中的數組(與通用集合不同)具有(並且一直具有)在運行時檢查它們的功能 - 即每次將元素放入它們時,都會檢查該元素是否是數組元素類型的實例它知道在運行時)。如果不是,它會拋出一個異常(ArrayStoreException)。

現在,考慮一下參數化類型的數組。假設你知道數組的上述行爲,你會期望一個參數化類型的數組將檢查放入它的東西是那個參數化類型的實例。除了Java在運行時檢查某些參數化類型的實例(ArrayList<Something>)是不可能的。你可以做的最多的是檢查它是一個ArrayList,但不是它的參數。由於它不會完全符合人們的期望,所以Java設計者決定完全禁止創建參數化類型數組。您仍然可以創建一個原始類型的數組(例如new ArrayList[5])或一個通配類型的數組(例如new ArrayList<?>[5]),因爲在這些情況下,它可以檢查對象是否是運行時的實例(即obj instanceof ArrayListobj instanceof ArrayList<?>是合法的,但obj instanceof ArrayList<Something>不是)。 (它們也可能創建了一個特殊情況,即參數化類型的數組只檢查元素是否針對原始類型,而不是參數化類型,但這會造成不一致。)但是,大多數遇到此問題的人並沒有考慮到該能力的數組在運行時檢查它們的元素類型 - 他們可能只是想創建一個正常使用的數組。

您也可以將數組轉換回參數化類型的數組。這是一個未經檢查的轉換,因爲如上所述,參數化類型的數組沒有辦法滿足數組的約定來完全檢查其元素類型 - 例如,現在如果您有ArrayList<String>[],則可以將ArrayList<Integer>添加到陣列中,而不會產生異常。然而,99%的人不關心這個特性,而這個不加控制的演員表示,嘿,我們知道這個限制,但我們仍然想要這樣做。

+0

如果你說你*可以*忽略警告,那麼爲什麼要打擾仿製藥和類型安全,而不是一直用rawtypes? :) – Natix

+0

@Natix:因爲你需要這樣做的唯一原因是未經檢查的轉換涉及大多數人不關心的數組方面(元素類型的運行時檢查)。在泛型中很多時候,有些東西不能在類型系統中表達(例如,將類映射到相應類類型的元素的映射),但是您可以通過可以證明的方式實現它。 – newacct