JDK原始碼之HashMap

2021-09-26 19:38:54 字數 2680 閱讀 5903

部分重要屬性

//存放key,value的陣列

transient node table;

//存放entry的set

transient set> entryset;

//hashmap的大小 預設16

transient int size;

//修改次數

transient int modcount;

//擴擴容閾值capacity * load factor

int threshold;

//擴容係數 預設0.75

final float loadfactor;

//node內部類

static class nodeimplements map.entry

public final k getkey()

public final v getvalue()

public final string tostring()

public final int hashcode()

public final v setvalue(v newvalue)

public final boolean equals(object o)

return false;

}}

hash函式以及hash槽位計算

static final int hash(object key) 

final nodegetnode(int hash, object key) while ((e = e.next) != null);}}

return null;

}

hash函式對key的hashcode進行邏輯右移16位,與原值進行異或運算(相同為0,不同為1)

對key進行hash函式之後與(size-1)進行相與運算(都為1才為1,其他為0),得到hash槽位

為什麼hash函式如此設計?

hashmap的大小一般小於2^17-1,進行hash槽位計算時只取低16位就夠了,但是這樣子hash衝突的可能性更大,試想一下,低16位相同,而高16位不同這樣的情況很多,把高16參與運算可以有效減少hash衝突

為什麼hashmap的大小建議為2的倍數?

hash槽位計算採用(n - 1) & hash,如果採用2的倍數,那麼槽位就是計算出的hash值的前幾位,比如n為32時,n-1的二進位制為

11111,假設有乙個key的hash值為11001101,那麼槽位就為01101即13;如果不為2的倍數,擴容時自動擴大容量為大於該值最近2的n次方的值

擴容

final node resize() 

else if ((newcap = oldcap << 1) < maximum_capacity &&

oldcap >= default_initial_capacity)

//擴容大小為原容量的兩倍

newthr = oldthr << 1; // double threshold

}else if (oldthr > 0)

//第一次put,且設定了初始容量,初始容量為設定的初始容量最接近的大於它的2的n次方值

newcap = oldthr;

else

if (newthr == 0)

threshold = newthr;

@suppresswarnings()

node newtab = (node)new node[newcap];

table = newtab;

//舊容擴新容過程

if (oldtab != null)

else

} while ((e = next) != null);

if (lotail != null)

if (hitail != null) }}

}}

return newtab;

}

resize方法觸發條件1.容量為空,第一次put的時候 2.容量不為空,但超過擴容閾值

設定新容量,新擴容閾值,包含3種情況,map不為空,map為空且設定初始容量,map為空且未設定初始容量

舊容擴新容過程

map putval

final v putval(int hash, k key, v value, boolean onlyifabsent,

boolean evict)

if (e.hash == hash &&

((k = e.key) == key || (key != null && key.equals(k))))

//鍊錶中已存在要放入的key值

break;

p = e;}}

if (e != null)

}++modcount;

if (++size > threshold)

//size大於擴容閾值,進行擴容

resize();

afternodeinsertion(evict);

return null;

}

紅黑樹轉化條件為hash槽位鍊錶長度大於8且table.length大於64;

JDK原始碼 HashMap 之resize

1.hashmap原始碼閱讀目標 了解具體的資料結構 hash及衝突鍊錶 紅黑樹 和重要方法的具體實現 hashcode equals put resize.2.重要方法 hashcode 與 equals都是在abstractmap中定義的 hashcode是各元素hash的累加 h iter.n...

jdk原始碼解析二之HashMap

hashmap的loadfactor為什麼是0.75?主要涉及到泊松分布的概念,猝 乙個bucket空和非空的概率為0.5,通過牛頓二項式等數學計算,得到這個loadfactor的值為log 2 約等於0.693.同回答者所說,可能小於0.75 大於等於log 2 的factor都能提供更好的效能,...

JDK原始碼學習 HashMap

什麼是hash?hash的意思是 雜湊 音譯做 雜湊 輸入乙個任意長度的資料,進過雜湊運算之後,輸出一段固定長度的資料,作為輸入資料的指紋,輸出的結果就是雜湊值。一般來說輸入資料的空間遠遠大於輸出的雜湊值的空間,輸入不同的資料可能會產生相同的雜湊值,所以很難從雜湊值來逆向推出輸入值是什麼。雜湊函式本...