1. 程式人生 > >容器HashMap原理(學習)

容器HashMap原理(學習)

技術分享 str 擴容 spa .cn .com 對象 ring ron

一、概述

基於哈希表Map 接口非同步實現,允許使用 null 值和 null 鍵,不保證映射的順序

二、數據結構

HashMap實際上是一個“鏈表散列”的數據結構,即數組和鏈表的結合體;HashMap 底層就是一個數組結構,數組中的每一項又是一個鏈表。當新建一個 HashMap 的時候,就會初始化一個數組。

技術分享

三、源碼解讀

put =>

當我們往 HashMap 中 put 元素的時候,先根據 key 的 hashCode 重新計算 hash 值,根據 hash 值得到這個元素在數組中的位置(即下標),如果數組該位置上已經存放有其他元素了,那麽在這個位置上的元素將以鏈表的形式存放

新加入的放在鏈頭,最先加入的放在鏈尾。如果數組該位置上沒有元素,就直接將該元素放到此數組中的該位置上。

get=>

在 HashMap 中要找到某個元素,需要根據 key 的 hash 值來求得對應數組中的位置。

對於任意給定的對象,只要它的 hashCode() 返回值相同,那麽程序調用 hash(int h) 方法所計算得到的 hash 碼值總是相同的。我們首先想到的就是把 hash 值對數組長度取模運算,這樣一來,元素的分布相對來說是比較均勻的。

而 HashMap 底層數組的長度總是 2 的 n 次方,這是 HashMap 在速度上的優化;

歸納:

HashMap 在底層將 key-value 當成一個整體進行處理,這個整體就是一個 Entry 對象。HashMap 底層采用一個 Entry[] 數組來保存所有的 key-value 對,當需要存儲一個 Entry 對象時,會根據 hash 算法

來決定其在數組中的存儲位置,在根據 equals 方法決定其在該數組位置上的鏈表中的存儲位置;當需要取出一個Entry 時,也會根據 hash 算法找到其在數組中的存儲位置,再根據 equals 方法從該位置上的鏈表中取出該Entry。

四、HashMap 什麽時候進行擴容呢(resize)

當 HashMap 中的元素個數超過數組大小 *loadFactor時,就會進行數組擴容,loadFactor的默認值為 0.75,默認情況下,數組大小為 16,那麽當 HashMap 中元素個數超過 16*0.75=12 的時候,就把數組的大小擴展為 2*16=32,即擴大一倍,然後重新計算每個元素在數組中的位置,而這是一個非常消耗性能的操作,所以如果我們已經預知 HashMap 中元素的個數,那麽預設元素的個數能夠有效的提高 HashMap 的性能

五、Fail-Fast 機制

java.util.HashMap 不是線程安全的,因此如果在使用叠代器的過程中有其他線程修改了 map,那麽將拋出 ConcurrentModificationException,這就是所謂 fail-fast 策略,叠代器的快速失敗行為應該僅用於檢測程序錯誤

六、遍歷方式

效率較高的:

 Map map = new HashMap();
  Iterator iter = map.entrySet().iterator();
  while (iter.hasNext()) {
  Map.Entry entry = (Map.Entry) iter.next();
  Object key = entry.getKey();
  Object val = entry.getValue();
  }

效率較低的:
 Map map = new HashMap();
  Iterator iter = map.keySet().iterator();
  while (iter.hasNext()) {
  Object key = iter.next();
  Object val = map.get(key);
  }
foreach方式:

 for(Entry<String, String> entry:hashmap.entrySet()){
System.out.println(entry.getKey()+"-->"+entry.getValue());
}


容器HashMap原理(學習)