【Java】の基礎——HashMap

哈希表

說道HashMap,不得不提起哈希表(即散列表)這個存儲結構。
平時我們在線性表(數組)中存儲數據,查找一個數據需要逐個比較。那麼有沒有什麼辦法能更快查找到數據呢?
舉個例子:

存儲 22 41 53 46 29 14 01 這7個數存在下標0-10的數組中

我們可以事先定義一個規則(稱爲-哈希函數):

H(k) = key%p
說白了就是對數組長度取餘數。
H(22)=22%11=0
H(41)=41%11=8
H(53)=53%11=9
H(46)=46%11=2
H(29)=29%11=7
H(14)=14%11=3
H(01)=01%11=1

存入數組結果是:
這裏寫圖片描述
在查找的時候我們只要把key按照規則運算然後去查找就可以了,這就是哈希表。

但是,如果此時再存入 24,H(24)=24%11=2
我們會發現,根據規則查找到的位置2已經被人佔用了,這種情況稱爲:哈希衝突。(本文就不從數據結構層面討論解決哈希衝突的辦法啦)

HashMap

Map

Map
提供了interface Entry

HashMap

首先我們看看HashMap的結構:
這裏寫圖片描述

首先,它定義了一個Node:

    Node<K,V>{
        int hash;
        K key;
        V value;
        Node<K,V> next;
    }

可以看出Node是一個鏈表的結點。

    Node<K,V>[] table;

而存儲的主體table,則是Node的數組。

HashMap還有兩個重要的值:

  • 加載因子(默認0.75):擴容的標準
  • 容量(初始值16):table的長度

我們可以結合HashMap創建的過程來看:

  • 首先默認創建一個長度爲16的數組。
  • 當存入對象時,根據key的hashcode值對HashMap的容量求餘數,決定該對象存放在數組中的位置。
    如果該位置已經有對象,則以鏈表的形式存儲(jdk1.8之前用頭插法,1.8用尾插法)。
  • 當然,如果table數組已經佔滿75%(根據加載因子0.75),那麼就對哈希表進行擴充,這個過程稱爲重新散列,將其容量擴大一倍。
  • 此外,在jdk1.8中,如果一個鏈表節點數大於8,那麼將其轉化爲紅黑樹進行存儲。

HashTable

HashMap是HashTable的輕量級實現,HashMap 不是線程安全
HashTable的方法都加了同步鎖,因此是線程安全的。相應的,它的效率也較低。

ConcurrentMap

ConcurrentMap是線程安全的Map。
ConcurrentHashMap的同步機制和HashTable不同,它不是加synchronized關鍵字,而是基於lock操作的,這樣的目的是保證同步的時候,鎖住的不是整個對象
一個ConcurrentHashMap裏包含一個Segment數組,Segment的結構和HashMap類似,是一種數組和鏈表結構, 一個Segment裏包含一個HashEntry數組,每個HashEntry是一個鏈表結構的元素, 每個Segment守護者一個HashEntry數組裏的元素,當對HashEntry數組的數據進行修改時,必須首先獲得它對應的Segment鎖。

TreeMap

TreeMap是一個有序的key-value集合,它是通過紅黑樹實現的。
該映射根據其鍵的自然順序(升序)進行排序,或者根據創建映射時提供的 Comparator 進行排序,具體取決於使用的構造方法。

LinkedHashMap

LinkedHashMap 是HashMap的一個子類,保存了記錄的插入順序,在用Iterator遍歷LinkedHashMap時,先得到的記錄肯定是先插入的.也可以在構造時用帶參數,按照應用次數排序。在遍歷的時候會比HashMap慢,不過有種情況例外,當HashMap容量很大,實際數據較少時,遍歷起來可能會比 LinkedHashMap慢,因爲LinkedHashMap的遍歷速度只和實際數據有關,和容量無關,而HashMap的遍歷速度和他的容量有關。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章