天天看點

Java集合架構:ArrayList

  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.

參考資料:

繼續閱讀