ArrayList以數組實作,允許重複。超出限制時會增加50%的容量(grow()方法中實作,如下所示),每次擴容都底層采用System.arrayCopy()複制到新的數組,是以最好能給出數組大小的預估值。預設第一次插入元素時建立數組的大小為10.
按數組下标通路元素—get(i)/set(i,e) 的性能很高,這是數組的基本優勢。
直接在數組末尾加入元素—add(e)的性能也高,但如果按下标插入、删除元素—add(i,e), remove(i), remove(e),則要用System.arraycopy()來移動部分受影響的元素,性能就變差了,這是基本劣勢。
ArrayList中有一個方法trimToSize()用來縮小elementData數組的大小,這樣可以節約記憶體:
考慮這樣一種情形,當某個應用需要,一個ArrayList擴容到比如size=10000,之後經過一系列remove操作size=15,在後面的很長一段時間内這個ArrayList的size一直保持在<100以内,那麼就造成了很大的空間浪費,這時候建議顯式調用一下trimToSize()這個方法,以優化一下記憶體空間。
或者在一個ArrayList中的容量已經固定,但是由于之前每次擴容都擴充50%,是以有一定的空間浪費,可以調用trimToSize()消除這些空間上的浪費。
非線程安全,可以調用Collections.synchronizedList(new ArrayList<>());實作。
舉個簡單一點的例子:
運作結果:
可以發現ArrayList是按插入順序存儲的,這也不奇怪,每次插入是在elementData[size++]處插入。
調用ArrayList中的subList方法生成的新的list,内部引用的還是原來的數組elementData,如果改變subList中的值,主list中的值也會跟着改變。
但是,上面的程式有不合理之處!你們可能感到費解,請聽我一一道來。
那麼這又有什麼不妥?集合架構印象中不就是用疊代器周遊的嚒?
注意ArrayList的特殊之處在于它implements了RandomAccess這個接口,在JDK中RandomAccess明确說明:
這段英文主要說明的是實作了RandomAccess接口的集合架構,采用疊代器周遊比較慢,不推薦。
實作RandomAccess接口的集合有:ArrayList, AttributeList, CopyOnWriteArrayList, RoleList, RoleUnresolvedList, Stack, Vector等。
是以上面的例子中的周遊應該這麼寫:
其實也可以加個判斷,讓程式通用起來:
是以,部落客個人覺得JDK(jdk7)中有這麼一段不妥之處(希望大神不要噴我):ArrayList的toString()方法是在AbstractCollection中實作的:
這裡沒有判斷RandomAccess,直接采用的是疊代器的周遊,影響了一些性能。
ArrayList是實作了基于動态數組的資料結構,LinkedList基于連結清單的資料結構。
對于随機通路get和set,ArrayList覺得優于LinkedList,因為LinkedList要移動指針。
對于新增和删除操作add和remove,LinkedList比較占優勢,因為ArrayList要移動資料。
Vector和ArrayList幾乎是完全相同的,唯一的差別在于Vector是同步類(synchronized),屬于強同步類。是以開銷就比ArrayList要大,通路要慢。正常情況下,大多數的Java程式員使用ArrayList而不是Vector,因為同步完全可以由程式員自己來控制。
Vector每次擴容請求其大小的2倍空間,而ArrayList是1.5倍。
Vector還有一個子類Stack.
參考資料: