ArrayList、LinkedList、與Vector的區別
- 解讀
- ArrayList 是一個可改變大小的數組
- LinkedList 是一個雙向鏈表
- Vector 屬強同步類
- 拓展知識面
- ArrayList是如何擴容?
- 如何利用List實現LRU?
解讀
List主要有ArrayList、LinkedList與Vector幾種實現。這三者都實現了List接口,使用方式也極其相似,主要區別在于因為實現方式的不同,所以對不同的操作就有不同的效率。
ArrayList 是一個可改變大小的數組
當,更多的元素加入到ArrayList中時,其大小將會動態的增長,內部的元素可以直接通過get與set方法進行訪問,因為ArrayList本質上就是數組。
LinkedList 是一個雙向鏈表
在添加和刪除元素的時間具有比ArrayList更好的性能,但是在get與set方面是弱于ArrayList。當然了,這些對比都是指數據量很大或者操作很頻繁的情況下的對比,如果數據量和運算量很小,那么就沒有對比的意義。
Vector 屬強同步類
Vector和ArrayList類似,但它屬于強同步類。如果你的程序本身是線程安全的(thread-safe,沒有在多個線程之間共享同一個集合或者對象),那么使用ArrayList是更好的選擇。
Vector和ArrayList在更多元素添加進來時會請求更大的空間。Vector每次請求是它自身大小的雙倍空間,而ArrayList每次對size增長50%。
而LinkedList還實現了Queue個Deque接口,該接口與List相比,其提供了更多的方法,包括offer()、peek()、poll()等。
注意:默認情況下ArrayList的初始容量非常小,所以如果可以預估數據量的話,分配一個較大的初始值才屬于最佳操作,這樣可以減少調整大小的開銷。
拓展知識面
ArrayList是如何擴容?
首先,我們要明白ArrayList是基于數組的,這個上面講到了,我們都知道,申請數組的時間,只能申請一個定長的數組,那么List是如何實現數組擴容的呢???ArrayList的擴容有幾個步驟:
- 檢查新增元素后是否會超過數組的容量,若超過,則進行下一步擴容;
- 設置新增容量為原始(舊/老)容量的1.5倍,最多不超過2^31-1(在Java8中ArrayList的容量最大是Integer.MAX_VALUE-8,這是由于在Java8中,ArrayList內部實現進行了一些改進,使用了一些數組復制的技巧來提高性能和內存的利用率,而這些技巧需要額外的8個元素的空間來進行優化)。
- 之后呢,申請一個容量為1.5倍的數組,將原有數組的元素復制到新數組中,自此,擴容完成。
如何利用List實現LRU?
LRU,即最近最少使用策略,基于時空局部性原理(最近訪問的,未來也會被訪問的),往往作為緩存淘汰的策略,如Redis和GuavaMap都使用了這種套胎策略。
我們可以基于LinkedList來實現LRU,因為LinkedList基于雙向鏈表,每個節點都會記錄上一個和下一個的節點,具體實現方式如下:
public class LruListCache<E> {private final int maxSize;private final LinkedList<E> list = new LinkedList<>();public LruListCache (int maxSize) {this.maxSize = maxSize;} public void add(E e) {if(list.size() < maxSize) {list.addFrist(e);}else{list.removeLast(); list.addFrist(e);}}public E get(int index) {E e = list.get(index);list.remove(e);add(e);return e;}@Overridepublic String toString() {return list.toString();}}
OK,如果不懂數組和鏈表的區別的話,隨后我有一個專門的數據結構的專欄,會講到棧和隊列、數組和鏈表以及二叉樹的遍歷等等內容。會做詳細解說。