在Java中,不能直接創建泛型數組的主要原因是類型擦除和類型安全問題。
類型擦除
Java中的泛型是通過類型擦除(Type Erasure)實現的,這意味著在編譯時,泛型類型會被轉換成原始類型(如 List<T>
會被轉換成 List
)。因此,運行時不會保留泛型的實際類型信息。例如,List<Integer>
和 List<String>
在編譯后都會變成 List
。由于類型擦除,在運行時無法區分不同的泛型類型。
類型安全
直接創建泛型數組會導致類型安全性問題。假設我們可以創建一個泛型數組:
List<String>[] stringLists = new List<String>[10];
然后我們可以通過類型轉換將其轉換為不同類型的泛型數組:
Object[] objects = stringLists; // 在數組中,子類數組是父類數組的子類,List是Object的子類
objects[0] = new ArrayList<Integer>();
這種情況下,運行時不會拋出異常,因為 ArrayList<Integer>
被視為 Object
,但在訪問 stringLists[0]
時,程序會期望 List<String>
,而實際上得到的是 List<Integer>
,這會導致 ClassCastException
。
示例和問題
以下是示例代碼,展示了直接創建泛型數組可能導致的問題:
List<String>[] stringLists = (List<String>[]) new List[10]; // 編譯時警告
List<Integer> intList = Arrays.asList(1, 2, 3);
Object[] objects = stringLists;
objects[0] = intList; // 運行時類型安全問題// 這將引發ClassCastException,因為stringLists[0] 實際上是一個 List<Integer>
String s = stringLists[0].get(0);
解決方法
由于直接創建泛型數組是不安全的,Java提供了其他安全的替代方法來處理類似情況。
使用集合
最推薦的方法是使用集合(如 List
)來替代數組:
List<List<String>> stringLists = new ArrayList<>(10);
for (int i = 0; i < 10; i++) {stringLists.add(new ArrayList<>());
}
使用原始類型數組加類型轉換
雖然不推薦,但可以使用原始類型數組并進行類型轉換:
List<String>[] stringLists = (List<String>[]) new List[10];
但這會產生編譯警告,且必須小心處理以避免類型安全問題。