標籤:com rom sorted link map對象 添加 迴圈 val 構造方法
集合類的架構圖:
HashMap
- 內部維護一個鏈表數組做雜湊表,預設大小為16,最大值可以為2^30,預設負載因子0.75。
- 可以通過構造方法指定初始大小和負載因子,當索引值對個數大於等於臨界值threshold(數組當前大小和負載因子的乘積)時對數組進行擴容,擴容策略為當前數組大小乘以2。
- 數組的每一項都是一個鏈表,鏈表的每個結點(靜態內部類Entry)都是索引值對,並緩衝了key的hash值。
- key 和value都可以為null,key為null時結點儲存在hash表數組下標為0的位置。
put過程:
public V put(K key, V value) { if (table == EMPTY_TABLE) { inflateTable(threshold); } if (key == null) return putForNullKey(value); int hash = hash(key); int i = indexFor(hash, table.length); for (Entry<K,V> e = table[i]; e != null; e = e.next) { Object k; if (e.hash == hash && ((k = e.key) == key || key.equals(k))) { V oldValue = e.value; e.value = value; e.recordAccess(this); return oldValue; } } modCount++; addEntry(hash, key, value, i); return null; }
- 通過key的hashcode計算出一個內部的hash值,然後用這個hash值對雜湊表大小取餘(演算法為h & (length-1),此處可以體現hash表length擴容策略為指數方式的優勢)定位到雜湊表的位置,然後遍曆該位置的鏈表,當遇到相等的key時,替換原來的value並將原來的value返回
- 如果沒找著key相同的記錄,就在相應位置添加新的鏈表結點,並將原來該位置的鏈錶鏈接到此節點後,此節點作為頭結點,當size大於閾值,則擴容到原來數組大小的兩倍
HashMap不是安全執行緒的,多線程環境下可能造成死迴圈(對hash表擴容後transfer資料時發生)或者遺失資料(hash衝突後添加新節點到鏈表時發生)。
HashSet
HashSet通過內嵌一個HashMap對象的方式來實現,通過HashMap的key來儲存,value都是相同的一個空Object()對象。與HashMap一樣,要求需要儲存的key實現hashcode和equals方法,且與HashMap具備同樣的初始大小和擴容策略。
TreeMap
紅/黑樹狀結構:一種大致平衡的二叉尋找樹,大致平衡是為了在保持較高檢索效率的同時還不需要頻繁調整,從而保持了統計上的效能。
- TreeMap內部使用了紅/黑樹狀結構來實現,維護其根節點,每個key-value都內嵌於其中一個節點(Entry),同時Entry還具有left、right、parent以及color屬性用以維持其樹形結構。
- 結點之間按key有序,需要key實現comparable介面或者在構造方法中傳入一個比較子comparator。
- 迭代時按key排序,儲存時會使用key的比較結果對key進行排重,只要比較結果相同就會被認為是同一份,此時儲存的key值為第一次put的key,value為第二次put進去的value
- 通過key get時,搜尋二叉尋找樹,找到匹配的返回其value,找不到返回null
- 通過value擷取時,遍曆所有節點搜尋
- TreeMap實現了SortedMap和NavigableMap介面,可以方便的根據鍵的順序進行尋找,如第一個、最後一個、某一範圍的鍵、鄰近鍵等。
- 根據鍵儲存、尋找、刪除的效率比較高,為O(h),h為樹的高度,在樹平衡的情況下,h為log2(N),N為節點數。
- TreeSet
- 內部持有一個TreeMap,類似HashSet,沒有重複元素,添加刪除判斷元素是否存在效率較高,為O(log2N),N為元素個數
- 有序,可以方便的根據順序進行尋找和操作,如第一個,最後一個,某一取值範圍,某一值的近鄰元素。
LinkedHashMap
- LinkedHashMap是HashMap的子類,內部有一個雙向鏈表維護索引值對的順序,每個索引值對既位於雜湊表中,也位於這個雙向鏈表中。
- 雙向鏈表的結點LinkedHashMap.Entry繼承自HashMap.Entry,添加了before和after兩個引用參數,同時重寫了HashMap.Entry的recordAccess和recordRemoval方法以維護和hash表中節點的關係。
- LinkedHashMap支援兩種順序,一種是插入順序,另一種是訪問順序,預設情況下按插入有序,構造方法中accessOrder設為true的時候按訪問順序,可以用來實現LRU緩衝(最近最少使用)
LinkedHashSet
LinkedHashMap也有一個對應的Set介面的實作類別LinkedHashSet。LinkedHashSet是HashSet的子類,但它內部的Map的實作類別是LinkedHashMap,所以它也可以保持插入順序
EnumMap
內部使用數組實現,構造方法需要傳入類型資訊。允許值為null,為了區分null和沒有值,用一個靜態全域唯一的new Integer(0)值來作為沒有值
EnumSet
內部使用位向量實現,是一個抽象類別,不能直接通過new關鍵字來建立,必須使用類似於noneOf的其他Factory 方法方法建立一個指定枚舉類型的set,實際建立的對象是EnumSet的子類RegularEnumSet或JumboEnumSet。
具體子類類型根據傳入的枚舉類型枚舉值的數量來決定:
- 小於等於64返回維護一個long變數(long為64位)作為位向量的子類RegularEnumSet
- 大於64返回一個內部維護long數組作為位向量的子類JumboEnumSet
下面是一些Factory 方法:
// 初始集合包括指定枚舉類型的所有枚舉值<E extends Enum<E>> EnumSet<E> allOf(Class<E> elementType)// 初始集合包括枚舉值中指定範圍的元素<E extends Enum<E>> EnumSet<E> range(E from, E to)// 初始集合包括指定集合的補集<E extends Enum<E>> EnumSet<E> complementOf(EnumSet<E> s)// 初始集合包括參數中的所有元素<E extends Enum<E>> EnumSet<E> of(E e)<E extends Enum<E>> EnumSet<E> of(E e1, E e2)<E extends Enum<E>> EnumSet<E> of(E e1, E e2, E e3)<E extends Enum<E>> EnumSet<E> of(E e1, E e2, E e3, E e4)<E extends Enum<E>> EnumSet<E> of(E e1, E e2, E e3, E e4, E e5)<E extends Enum<E>> EnumSet<E> of(E first, E... rest)// 初始集合包括參數容器中的所有元素<E extends Enum<E>> EnumSet<E> copyOf(EnumSet<E> s)<E extends Enum<E>> EnumSet<E> copyOf(Collection<E> c)
Java集合總結(二):Map和Set