容器HashMap原理(學習)
一、概述
基於哈希表的 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 算法
四、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原理(學習)