編譯器可以自發地進行轉換,他們只是規定不因爲通用陣列不能表現像非泛型數組。
參見10.5. Array Store Exception:
對於數組類型爲A[]
,其中A
是引用類型,分配到該陣列的一個組件在運行時進行檢查,以確保所分配的值是分配到組件。
如果所分配的值的類型與組件類型不是分配兼容的,則會引發ArrayStoreException
。
如果數組的組件類型不可確定,則Java虛擬機無法執行上一段中描述的存儲檢查。這就是爲什麼禁止使用不可指定元素類型的數組創建表達式的原因。
如果我們把一些其他種類的List
在它List<MyDTO>[]
不會丟,所以它不表現爲一個數組。請注意報價中的最後一句:「這就是爲什麼禁止使用不可指定元素類型的數組創建表達式。」這就是原因,它被指定爲這樣。 (而且,備案,this reasoning has always existed,所以它是存在,當這個問題被張貼在2011年)
我們仍然可以做到這一點:
@SuppressWarnings({"unchecked","rawtypes"})
List<MyDTO>[] dtoLists = new List[] {
new ArrayList<MyDTO>(), anExistingDtoList
};
或者這樣:
@SuppressWarnings("unchecked")
List<MyDTO>[] dtoLists = (List<MyDTO>[]) new List<?>[] {
new ArrayList<MyDTO>(), anExistingDtoList
};
(除了靜態地檢查參數類型之外,可變參數的東西是等價的:它可以是creates a List[]
和suppresses warnings。)
現在,當然,規範可以改變「如果所分配的值的類型與的原始類型的元件類型...」不是分配兼容的,但是要點是什麼?它會在一些不尋常的情況下保存少數人物,但是否則會禁止那些不瞭解其含義的人發出警告。
此外,我看到the tutorial和其他典型解釋沒有證明的是如何烘焙到類型系統協變陣列。
例如,給出如下聲明:
// (declaring our own because Arrays.fill is defined as
// void fill(Object[], Object)
// so the next examples would more obviously pass)
static <T> void fill(T[] arr, T elem) {
Arrays.fill(arr, elem);
}
你知道,這個編譯?
// throws ArrayStoreException
fill(new String[1], new Integer(0));
而這個編譯過:
static <T, U extends T> void fill(T[] arr, U elem) {...}
但是,這只是一個:
// doesn't throw ArrayStoreException
fill(dtoLists, new ArrayList<Float>());
的Java 8之前,我們可以到fill
失敗給它下面的聲明使這些電話類型推斷問題,現在它工作「正確」,一味地將List<Float>
放入List<MyDTO>[]
。
這叫做堆污染。它可能會導致ClassCastException
在某個時間後拋出,可能與實際導致問題的操作完全無關。像List
這樣的通用容器造成的堆污染需要更加明顯的不安全行爲,例如使用raw types,但在這裏,我們可以隱式導致堆污染,並且不會有任何警告。
通用數組(通常是數組)實際上只允許我們在最簡單的情況下進行靜態檢查。
因此很明顯,語言設計者認爲最好不要讓他們,而瞭解他們存在問題的程序員可以抑制警告並繞過限制。
[Array of Generic List](http://stackoverflow.com/questions/7810074/array-of-generic-list) – Thilo
的可能重複檢查出該重複的最佳答案。它有一個例子,爲什麼這是不被允許的。 – Thilo
這不是重複的。我的問題要求有關編譯器設計問題的答案。 –