1. 程式人生 > 其它 >Java集合之Map

Java集合之Map

一、Map的實現類的結構

Map:雙列資料,儲存key-value對的資料 --- 類似於高中的函式:y=f(x) (JDK1.2才有)

  • HashMap:(1.2才有)作為Map的主要實現類;執行緒不安全,效率高;儲存null的key和value
  • LinkedHashMap:(1.4才有)保證在遍歷map元素時,可以按照新增的順序實現遍歷。
    • 原因:在原有的HashMap底層結構基礎上,添加了一對指標,指向前一個和後一個元素。
    • 對於頻繁的遍歷操作,此類執行效率高於HashMap。
  • TreeMap:(1.2才有)保證按照新增的key-value對進行排序,實現排序遍歷。此時考慮key的自然排序或定製排序,底層使用紅黑樹
  • Hashtable:(1.0時就有)作為古老的實現類;執行緒安全的,效率低;不能儲存null的key和value
    • Properties:常用來處理配置檔案。key和value都是String型別

HashMap的底層:

  • 陣列+連結串列(jdk7及之前)
  • 陣列+連結串列+紅黑樹(jdk8)

面試題:

  1. HashMap的底層實現原理?
  2. HashMap 和 Hashtable的異同?
  3. CurrentHashMap 與 Hashtable的異同?(暫時不講)

二、Map結構的理解

  • Map中的key:無序的、不可重複的,使用Set儲存所有的key ---> key所在的類要重寫equals()和hashCode() (以HashMap為例)
  • Map中的value:無序的、可重複的,使用Collection儲存所有的value ---> value所在的類要重寫equals()
  • 一個鍵值對:key-value構成了一個Entry物件。
  • Map中的entry:無序的、不可重複的,使用Set儲存所有的entry

三、HashMap的底層實現原理

以jdk7為例說明
在HashMap例項化以後,底層建立了長度是16的一維陣列Entry[] table。
--- 可能已經執行過多次put ---
map.put(key1,value1);
首先,呼叫key1所在類的hashCode()計算key1雜湊值,此雜湊值經過某種演算法計算以後,得到在Entry陣列中的存放位置。

  • 如果此位置上的資料為空,此時的key1-value1新增成功。 ----情況1
  • 如果此位置上的資料不為空,(意味著此位置上存在一個或多個數據(以連結串列形式存在)),比較key1和已經存在的一個或多個數據的雜湊值:
    • 如果key1的雜湊值與已經存在的資料的雜湊值都不相同,此時key1-value1新增成功。 ----情況2
    • 如果key1的雜湊值與已經存在的某一個數據(key2-value2)的雜湊值相同,繼續比較:呼叫key1所在類的equals(key2)方法,比較:
      • 如果equals()返回false:此時key1-value1新增成功。 ----情況3
      • 如果equals()返回true:使用value1替換value2。

補充:關於情況2和情況3:此時key1-value1和原來的資料以連結串列的方式儲存。

在不斷的新增過程中,會涉及到擴容問題,當超出臨界值(且要存放的位置非空)時則擴容,預設的擴容方式:擴容為原來容量的2倍,並將原有的資料複製過來。

jdk8相較於jdk7在底層實現方面的不同

  1. new HashMap():底層沒有建立一個長度為16的陣列
  2. jdk8底層的陣列是:Node[],而非Entry[]
  3. 首次呼叫put()方法時,底層建立長度為16的陣列
  4. jdk7底層結構只有:陣列+連結串列。jdk8中底層結構:陣列+連結串列+紅黑樹。
    在jdk8中,當陣列的某一個索引位置上的元素以連結串列形式存在的資料個數 > 8 且當前陣列的長度 > 64時,
    此時此索引位置上的所有資料改為使用紅黑樹儲存。

HashMap原始碼中的一些常量

DEFAULT_INITIAL_CAPACITY:HashMap的預設容量,16
DEFAULT_LOAD_FACTOR:HashMap的預設載入因子:0.75
threshold:擴容的臨界值 = 容量填充因子 :160.75 = 12
TREEIFY_THRESHOLD:Bucket中連結串列長度大於該預設值,轉化為紅黑樹:8
MIN_TREEIFY_CAPACITY:桶中的Node被樹化時最小的hash表容量:64

四、LinkedHashMap的底層實現原理(瞭解)

原始碼中:

        static class Entry<K,V> extends HashMap.Node<K,V> {
            Entry<K,V> before, after;//能過記錄新增的元素的先後順序
            Entry(int hash, K key, V value, Node<K,V> next) {
                super(hash, key, value, next);
            }
        }