[英]Why does Java ArrayList use per-element casting instead of per-array casting?
Java的ArrayList<T>
(可能還有很多其他類)中發生的事情是內部Object[] array = new Object[n];
,寫入T
對象。 每當從中讀取一個元素時,一個強制轉換return (T) array[i];
已經完成了。 所以,每次閱讀時都要施展。
我想知道為什么這樣做。 對我來說,似乎他們只是做了不必要的演員表。 創建一個T[] array = (T[]) new Object[n];
是不是更合乎邏輯,也更快一點T[] array = (T[]) new Object[n];
然后只return array[i];
沒有演員? 這只是每個數組創建一個強制轉換,通常遠遠小於讀取次數。
為什么他們的方法是首選的? 我不明白為什么我的想法不是更嚴格?
它比這更復雜:泛型以字節代碼擦除, T[]
的擦除是Object[]
。 同樣, get()
的返回值變為Object
。 為了保持類型系統的完整性,在實際使用類時插入檢查的強制轉換,即
Integer i = list.get(0);
將被刪除
Integer i = (Integer) list.get(0);
既然如此,ArrayList中的任何類型檢查都是多余的。 但它確實不重要,因為(T)
和(T[])
都是未經檢查的強制轉換,並且不會產生運行時開銷。
可以編寫一個檢查過的ArrayList:
T[] array = Array.newInstance(tClass, n);
這樣可以防止堆污染 ,但代價是冗余類型檢查(你無法抑制調用代碼中的合成轉換)。 它還需要調用者為ArrayList提供元素類型的類對象,這會使其api變得混亂並使其在通用代碼中更難使用。
編輯:為什么禁止創建通用數組?
一個問題是檢查數組,而未檢查泛型。 那是:
Object[] array = new String[1];
array[0] = 1; // throws ArrayStoreException
ArrayList list = new ArrayList<String>();
list.add(1); // causes heap pollution
因此,陣列的組件類型很重要。 我假設這就是Java語言的設計者要求我們明確使用哪種組件類型的原因。
每當從中讀取一個元素時,一個強制轉換
return (T) array[i];
已經完成了。 所以,每次閱讀時都要施展。
Generic是編譯時檢查。 在運行時,使用類型T extends代替。 在這種情況下, T
隱式extends Object
因此您在運行時所擁有的是有效的。
return (Object) array[i];
要么
return array[i];
創建一個不是更合乎邏輯,也更快一點
T[] array = (T[]) new Object[n]
並不是的。 在運行時再次成為
Object[] array = (Object[]) new Object[n];
要么
Object[] array = new Object[n];
你真正釣魚的是
T[] array = new T[n];
除了這不編譯,主要是因為T在運行時不知道。
你能做的是
private final Class<T> tClass; // must be passed in the constructor
T[] array = (T[]) Array.newInstance(tClass, n);
只有這樣,數組實際上才是預期的類型。 這可以使讀取速度更快,但代價是寫入。 主要的好處是快速檢查失敗,即你會阻止一個集合被破壞,而不是等到你發現它被破壞后拋出異常。
我認為更多的是代碼風格而不是性能或類型安全(因為支持數組是私有的)
java 5 ArrayList
實現方式與您對E[]
數組的建議方式相同。 如果您查看源代碼,您會看到它包含7個(E [])強制轉換。 從java 6開始, ArrayList
更改為使用Object[]
數組,該數組僅導致3(E)個轉換。
數組也是對象。 這里T[] array = (T[]) new Object[n]
你只投射(T [])對象類型而不是數組中的元素。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.