比較經常使用的集合通常有4種接口,每種接口能夠由多種數據結構去實現。這樣咱們就能夠在實現相同接口(功能)的狀況下,根據具體場景選擇不一樣的數據結構。java
Interface | Hash Table | Resizable Array | Balanced Tree | Linked List | Hash Table + Linked List |
---|---|---|---|---|---|
Set | HashSet | TreeSet | LinkedHashSet | ||
List | ArrayList | LinkedList | |||
Deque | ArrayDeque | LinkedList | |||
Map | HashMap | TreeMap | LinkedHashMap |
ArrayList、LinkedList、Vector都實現了接口List。List接口是一個有順序的集合,元素能夠重複,能夠經過索引去訪問元素。api
ArrayList類維護了一個數組,訪問操做效率高,刪除和插入操做效率低。數組
transient Object[] elementData; // non-private to simplify nested class access
當增長元素且ArrayList的容量不夠時,須要對數組進行擴容,擴容使用Arrays.copyOf()
方法。
當刪除元素時,會使用System.arraycopy()
方法。
以上兩個copy方法都是蠻費時間的。緩存
LinkedList類維護了一個雙端鏈表,first和last分別指向鏈表的頭尾Node。安全
Vector類與ArrayList類很是相像,主要的區別是:Vector是線程安全的,ArratList不是線程安全的。數據結構
protected Object[] elementData;
Stack類繼承了Vector類,由於Vector類維護了一個數組,在數組基礎上實現LIFO的功能仍是很方便的。但這也會帶來2個問題:oracle
setElementAt(E obj, int index)
,那麼Stack就不是純粹的棧,棧只能操做棧頂的元素。JDK文檔建議,若是要使用棧這種數據結構,應該優先使用Deque<Integer> stack = new ArrayDeque<Integer>();
優化
Deque是Double End Queue
的意思,該雙端隊列便可以用做FIFO的隊列,也能夠用做LIFO的棧。Stack類也是棧,但它有些缺點,應該優先使用Deque做爲棧。線程
LinkedList類維護了一個雙端鏈表,first和last分別指向鏈表的頭尾Node。code
ArrayDeque是在JDK1.6中才出現的。以數組的形式實現雙端隊列。
JDK文檔建議:
第1點的緣由在上面說過解釋過,第2點的緣由有如下兩點:
HashMap(散列表)是一個增刪、查找都高效的數據結構。查找散列表通常分爲2個步驟:
java中的HashMap採用的是拉鍊法,這是數組和鏈表的結合形式。
HashMap中的put()方法:
hash%length
,length是數組的長度。該長度應該是2的冪方,這樣咱們就能夠對取模操做進行優化hash&(length-1)
靜態內部類Entry
中。Entry保存鍵、值以及指向下一個鍵值對的next。HashMap中的resize()方法:
當entry的數量大於閾值時,開始resize()。其中閾值是容量乘以加載因子。
resize()以後,table長度變爲2倍,從新取模,從新鏈表插入。
負載因子:當hashmap中的有效容量除以總容量大於負載因子時,hashmap的容量就會翻倍。java的hashmap默認容量是16,負載因子時0.75。
容量:
Java8對HashMap的改進:當鏈表的長度大於必定值時,鏈表就轉換爲紅黑樹,實現了快速的增刪改查,時間複雜度從順序查找的O(n)優化到O(logn)。
HashTable與HashMap很是類似,他們有如下三點區別:
【Reference】