更新:這個回答得到了更多的關注和upvotes比我認爲它應得的基本上覆制粘貼的JDK源代碼,所以我會嘗試把它變成值得的東西。
Java泛型的設計看起來像是真實的,具體化的,多實例,C++ - 或C#泛型風格。這意味着對於像ArrayList<E>
這樣的類型,我們預計ArrayList<String>
的行爲與每個出現的E
已被替換爲String
一樣。換句話說,這樣的:
private Object[] elementData = new Object[size];
public E get(int i) {
return (E) elementData[i];
}
String str = list.get(0);
應該成爲這樣的:
private Object[] elementData = new Object[size];
public String get(int i) {
return (String) elementData[i];
}
String str = list.get(0);
現在,你可能知道,那並不是他們如何工作。對於現在(大部分)很長時間後面的兼容性原因,Java泛型是通過類型擦除實現的,其中E
實際上被替換爲Object
,並且鑄造到String
被插入到中,並在需要時調用代碼。這意味着該代碼實際上變成是這樣的:
private Object[] elementData = new Object[size];
public Object get(int i) {
return elementData[i];
}
String str = (String) list.get(0);
演員到(E)
已經消失,並在調用點又出現了。如果通話網站忽略了結果,劇組將完全消失!這就是爲什麼它給出了「未經檢查」的警告。
現在想象一下,如果elementData
有型E[]
相反,你的建議。也就是說,代碼如下所示:
private E[] elementData = (E[]) new Object[size];
public E get(int i) {
return elementData[i];
}
String str = list.get(0);
由於擦除,我們知道它被轉換爲與上述相同的東西。但是如果我們有具體化的泛型像我們希望我們所做的,它應該是這樣的:
private String[] elementData = (String[]) new Object[size];
// ClassCastException: Object[] is not a String[]
本質上講,我們已經寫了一些代碼,將會在運行時崩潰,它在所有工作的唯一原因是,Java的泛型實施假裝比現在更好。我們向編譯器撒謊以說服它接受脆弱的代碼。
它很脆!我們碰巧避免了運行時崩潰,因爲數組永遠不會轉義類。但是如果這樣做的話,它會導致難以預測的地方出現ClassCastException
。如果Java 9引入了泛化的泛型呢?第一個實現會繼續工作,但是這個會破壞。
這就是爲什麼大多數合理的Java編碼規範要求非檢查類型轉換爲類型正確的原因。 (E) elementData[i]
是類型正確的,因爲ArrayList
確保只有E
s可以存儲在elementData
中。 (E[]) new Object[size]
從來沒有類型正確,除非E
是Object
。
還有其他的好處。在Java 8中,elementData
字段可以具有特殊的哨兵值:
/**
* Shared empty array instance used for empty instances.
*/
private static final Object[] EMPTY_ELEMENTDATA = {};
/**
* Shared empty array instance used for default sized empty instances. We
* distinguish this from EMPTY_ELEMENTDATA to know how much to inflate when
* first element is added.
*/
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
/**
* The array buffer into which the elements of the ArrayList are stored.
* The capacity of the ArrayList is the length of this array buffer. Any
* empty ArrayList with elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA
* will be expanded to DEFAULT_CAPACITY when the first element is added.
*/
transient Object[] elementData; // non-private to simplify nested class access
您似乎認爲「E」是真實的。這是你想象中的無花果牛頓。在ArrayList類被編譯時,數組的類是固定的,回到Java代工中。 – 2014-09-05 22:59:23
@HotLicks「據我所知,編譯器運行後,類型擦除將E []轉換爲Object []」..「如果使用它E [],下面的代碼[它不是]必須[使用強制轉換]」 – user2864740 2014-09-05 23:00:04
聲明E []可能會改進源代碼,但最終的編譯結果將是相同的。 – 2014-09-05 23:00:28