hashmap原始碼解析系列文章
jdk8 hashmap原始碼行級解析 史上最全最詳細解析
jdk8 hashmap原始碼行級解析 紅黑樹操作 史上最全最詳細**
jdk8 hashmap原始碼 putmapentries解析
jdk8 hashmap原始碼 clone解析
深入理解hashmap:那些巧妙的位操作
聽說你看過hashmap原始碼,來面試下這幾個問題
entry table
。這個entry型別的陣列儲存了hashmap的真正資料。
size
大小。代表hashmap內儲存了多少個對映。
capacity
容量。實際上hashmap沒有乙個成員叫capacity,它是作為table這個陣列的大小而隱式存在。
threshold
閾值和loadfactor
裝載因子。threshold是通過capacity * loadfactor得到的。當size超過threshold時(剛好相等時不會擴容),hashmap會擴容再雜湊。
entryset
、keyset
和values
這三個都是一種檢視,真正的資料都來自table
。
這是為了能夠通過&
位操作來得到乙個對映的所在table陣列下標。
正常來說,通過key的hash值 % table.length
可以得到key所應該在的陣列下標,但如果這個容量是2的冪,那麼 陣列下標可以通過key的hash值 & (table.length-1)
得到。位操作肯定比取餘操作快多了。
通過hash實現了對對映的快速訪問。key可以有乙個null,value可以重複。
非同步,是執行緒不安全的。單執行緒下,使用hashmap相比使用hashtable效率更高。
底層是hash表,所以不保證順序。因為每次resize都會重新分配元素到各個雜湊桶。
首先判斷table成員是否初始化,如果沒有,則呼叫resize。
通過傳入鍵值對的key
的hashcode和容量,馬上得到了該對映所在的table陣列下標。並通過陣列的取下標操作,得到該雜湊桶的頭節點。
如果沒有發生雜湊碰撞(頭節點為null),那麼直接執行新增操作。
如果發生了雜湊碰撞(頭節點不為null),那麼分為兩種情況:
如果與桶內某個元素==
返回true,或者equals判斷相同,執行替換操作。
如果與桶內所有元素判斷都不相等,執行新增操作。
新增操作做完後會有兩個判斷:
如果雜湊桶是單鏈表結構,且桶內節點數量超過了treeify_threshold(8),且size大於等於了min_treeify_capacity(64),那麼將該雜湊桶轉換為紅黑樹結構。
如果新增後size大於了threshold,那麼呼叫resize。
當table還沒初始化時,使用預設容量16或者通過使用者給定容量算出乙個2的冪,來作為table的大小。
當table已經初始化了,那麼擴容成舊容量的2倍。如果新容量為最大容量,則將閾值設為int最大值。
當table已經初始化,且舊容量已經是最大容量,那麼table不再進行擴容。
雜湊桶內的各個元素,經過擴容後,它的可能的table下標要麼在原table下標
,要麼在原table下標 + 舊容量
。正是因為容量永遠為2的冪,才使得擴容操作如此簡單。
通過傳入對映的key
的hashcode和容量,馬上得到了該對映所在的table陣列下標。並通過陣列的取下標操作,得到該雜湊桶的頭節點。
如果頭節點為null,那麼代表沒有該對映。
如果頭節點不為null,且傳入對映與桶內某個對映==
返回true,或者equals判斷相同,那麼代表找到了該對映。
如果頭節點不為null,且傳入對映與桶內每個對映都判定不相等,那麼代表沒有該對映。
將key
的hashcode與該hashcode的無符號右移16位,異或起來得到的。
因為當table的size比較小時,能影響到table下標的,只有雜湊值幾個低位bit,這很可能會加劇雜湊碰撞。但這樣實現後,雜湊值的高16位bit保持不變,低16位則受到高16位的「擾動」而發生改變,這樣就使得高位bit也能影響table下標,減少雜湊碰撞。
key
的hashcode只要有乙個bit發生變化,hash函式的返回值也會跟著變化,用以減少雜湊碰撞。
如果key重寫了hashcode方法,那麼也應該重寫equals方法。
如果key只重寫了hashcode方法,卻沒有重寫equals方法。那麼會造成map裡會存在重複的我們認為「相同」的鍵值對在裡面(一般是指,兩個物件的成員是相同的)。因為如果新增了相同元素,根據put過程則發生雜湊碰撞,本來這個相同元素不應該新增,但由於原始object的equals方法邏輯使用==
判斷,所以只要位址值不同就肯定能新增進去。
如果key只重寫了equals方法,卻沒有重寫hashcode方法。那麼也會造成map裡會存在重複的我們認為「相同」的鍵值對在裡面。因為使用了原始的hashcode了,有些該發生的雜湊碰撞也就不會發生了,都不在乙個雜湊桶了,即使我們認為是「相同」的,也不會去呼叫你重寫的equals方法的。
本文基於jdk1.8的hashmap原始碼。
HashMap原始碼系列 HashMap的屬性
public class hashmap extends abstractmap implements map,cloneable,serializable容載因子 容載因子越大,table陣列中儲存的資料越密集,碰撞的可能性就越大。容載因子越小,儲存越稀疏,碰撞的可能性就越小,不過浪費儲存空間。轉...
HashMap原始碼解讀
一 建立乙個hashmap都做了哪些工作?mapmap new hashmap hahmap無參構造方法 public hashmap 可以看到設定了載入因子 預設0.75 閾值 預設容量16 預設載入因子0.75 12 table是hashmap內部資料儲存結構entry陣列。當hashmap的s...
HashMap原始碼分析
public hashmap int initialcapacity,float loadfactor 2 接下來是重要的put方法,put方法用於將鍵值對儲存到map中,讓我們來具體分析一下。public v put k key,v value if key null 若key為null,則將va...