1. 程式人生 > >HashMap原理簡單認識

HashMap原理簡單認識

1. hashMap簡單認識

優點:hashMap的儲存方式是鍵值對(鍵可以包括null),查詢速度儲存方便儲存數量最大為十幾億

缺點:主要是執行緒不安全,容易在hashmap擴容時形成死迴圈

2.hashMap從原始碼角度簡單認識

jdk1.7 使用的陣列 + 連結串列

jdk1.8 使用的陣列 + 連結串列 + 紅黑樹

分析為什麼使用陣列 + 連結串列 + 紅黑樹:

陣列:主要是方便查詢,且在記憶體中是連續的。

連結串列:主要是方便插入,刪除,然而hashMap把兩個者有點結合在一起。

紅黑樹:主要是jdk1.8為了對連結串列進行優化時,增加的資料結構。那麼在它們如何使用的呢? ,可以從put()

函式中看出

hashmap重要引數
loadFactor 負載因子,預設值75%
threshold 臨界值,超過臨界值需要重新分配
modCount 統計刪除和修改的次數
Entry 實體類,主要有四個引數組成,分別是key,hash,value,next

hashmap的建構函式

    1.無參構造

     

    2.有參構造

    

    

    分析hashmap的建構函式:

  通過在平時專案觀察發現,大部分人都會使用無參的建構函式,因為會有初始值16,那麼問題來了,如果我們儲存數量大於16  呢,看過原始碼的人當然會說,需要進行擴容操作,可是資料量比較大的時候是不是申請很多記憶體空間,把一個數組裡面的資料重新放到另一個數組裡面去,這樣可能比較消耗時間和記憶體,如果在多執行緒情況下,是不是容易出現數據問題,我個人觀點,提前指定所需要的空間,那麼有人會說,我可以知道需要申請多少空間,如果盲目申請記憶體是不是也會產生浪費,這樣的觀點是沒有錯的,但是我這裡強調的是,在你大概知道需要多少資料量,應指定所需要申請的空間。

hashmap裡面的put操作

addEntry函式:

createEntry:

putForNullKey函式:

hashMap裡面put方法:

1.  首先初始化陣列

2.  判斷鍵是不是null,如果是null,用putForNullKey()來處理

3. 計算出雜湊值

4. 用雜湊值和陣列長度進行indexFor()運算;得到下標i;

5. 通過下標i在數組裡面找到對應的實體類,比較實體類裡面hash值和key的==和equals方法,都相等的話,說明是要找的value

否則話,進行增加實體類

6. 在增加實體類時,都會進行判斷,是否超過threshold值,如果超過就把原來陣列的大小變為2倍。

分析put方法:

可以從原始碼和上述過程中,可以看出,在進行put操作時,首先會進行雜湊值進行比較,然後在比較key的==和equal方法,那麼在什麼時候使用equal方法呢?,其實涉及到一個雜湊衝突的問題,就是hashcode可能存在衝突,最後會和buckIndex的值一樣,在這一種情況下,會呼叫equal方法,因為equal是Object方法,它直接比較的是記憶體大小。

hashmap裡面的put操作通過hashcode值可以存放資料。當不同物件的雜湊值相同時,會通過單鏈表的方式解決,將新元素插入表頭,它的next指向原來的元素。(為什麼插入表頭不插入表尾,正在研究)

分析put方法的執行緒不安全:

hashmap很容易在put操作時,形成死迴圈。

分析死迴圈形成的原因:

1. 從上述原始碼中,可以看出死迴圈的原因主要是因為在進行擴容操作所造成的。

2. 首先把原來的大小變為2倍。

3. 遍歷原來的陣列

4. 因為是單鏈表,所以要儲存下一個節點, Entry<k,v> next = e.next;

5. 因為e要插入表頭,並且需要e指向連結串列的第一個元素,所以需要把e.next = newTable[i];

6. 然後讓e變為陣列的頭指標。newTable[i] = e;

其實上述過程實際是單向連結串列的反轉,在形成死迴圈時,主要是在第4 ,5 ,6步。

3.hashmap所涉及到的資料結構

  1. 連結串列

  2. 雜湊運算

  3. 紅黑樹(jdk1.8自己正在研究中)