jdk原始碼解析二之HashMap

2021-10-07 16:32:19 字數 4073 閱讀 8455

hashmap的loadfactor為什麼是0.75?

主要涉及到泊松分布的概念,猝!!!

乙個bucket空和非空的概率為0.5,通過牛頓二項式等數學計算,得到這個loadfactor的值為log(2),約等於0.693. 同回答者所說,可能小於0.75 大於等於log(2)的factor都能提供更好的效能,0.75這個數說不定是 pulled out of a hat。

public v put

(k key, v value)

static

final

inthash

(object key)

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))))

break

; p = e;}}

//更新key的值

if(e != null)

}//記錄修改次數

++modcount;

//超過限制容量,擴容if(

++size > threshold)

resize()

;//空操作

afternodeinsertion

(evict)

;return null;

}

public v remove

(object key)

final node

removenode

(int hash, object key, object value,

boolean matchvalue,

boolean movable)

p = e;

}while

((e = e.next)

!= null);}

}if(node != null &&

(!matchvalue ||

(v = node.value)

== value ||

(value != null && value.

equals

(v))))

}return null;

}

@override

public v replace

(k key, v value)

return null;

}final node

getnode

(int hash, object key)

while

((e = e.next)

!= null);}

}return null;

}

public v get

(object key)

final node

resize()

elseif(

(newcap = oldcap <<1)

< maximum_capacity &&

oldcap >= default_initial_capacity)

//如果擴容後的大小newthr = oldthr <<1;

// double threshold

}else

if(oldthr >0)

// initial capacity was placed in threshold

newcap = oldthr;

else

if(newthr ==0)

threshold = newthr;

@suppresswarnings()

//臨時儲存擴容後的值

node

newtab =

(node

)new

node

[newcap]

;//在整個擴容節點,table為空

table = newtab;

//以下執行擴容操作

if(oldtab != null)

else

}while

((e = next)

!= null)

;//為什麼擴容後,相同的在原位置儲存,而不同的則當前索引+之前原位置索引儲存?

//因為這裡的擴容都是擴容一倍,也就是01000擴容後變成10000

// 當e.hash & oldcap == 0,說明hash《當前容量,也就是落在0~1000範圍內,哪怕擴容後,進行&操作也是一樣的索引值

//!=0,則說明第一e.hash落在0~1000範圍內,第二包含1000這個位置.而1000是之前擴容前的容量,所以最新的位址為擴容前容量+當前索引

//原位置儲存

if(lotail != null)

//儲存索引在擴容的那部分

if(hitail != null)}}

}}return newtab;

}

final node

nextnode()

while

(index < t.length &&

(next = t[index++])

== null);}

return e;

}

jdk8中,改變了底層資料結構,為線性表+鍊錶+紅黑樹

產生hash值碰撞後,用鍊錶儲存碰撞的值

什麼時候採用紅黑樹?

當桶裡面存的鍊錶個數》8,同時陣列長度》64,的時候採用紅黑樹

預設載入因子0.75

預設容量16,載入擴容的大小12

key一樣時,覆蓋舊的value

可以存null,索引0

為什麼每次擴容後,是2的冪次方?

是因為在使用2的冪的數字的時候,length-1的值是所有二進位制位全為1,這種情況下,index的結果等同於hashcode後幾位的值。

只要輸入的hashcode本身分布均勻,hash演算法的結果就是均勻的。

這是為了實現均勻分布。

為什麼擴容後,相同的在原位置儲存,而不同的則當前索引+之前原位置索引儲存?

//因為這裡的擴容都是擴容一倍,也就是01000擴容後變成10000

// 當e.hash & oldcap == 0,說明hash《當前容量,也就是落在0~1000範圍內,哪怕擴容後,進行&操作也是一樣的索引值

//!=0,則說明第一e.hash落在0~1000範圍內,第二包含1000這個位置.而1000是之前擴容前的容量,所以最新的位址為擴容前容量+當前索引

//原位置儲存

if(lotail != null)

//儲存索引在擴容的那部分

if(hitail != null)

為啥用尾插法?

jdk7因為頭插法存在環形問題

而jdk8,使用尾插,在擴容時會保持鍊錶元素原本的順序,就不會出現鍊錶成環的問題了

為什麼執行緒不安全?

在jdk1.7中,在多執行緒環境下,擴容時會造成環形鏈或資料丟失。

在jdk1.8中,在多執行緒環境下,會發生資料覆蓋的情況。

原始碼解析 JDK原始碼之LinkedHashMap

linkedhashmap原始碼,基於 jdk1.6.43 他繼承了hashmap,並且實現了插入和訪問的有序功能 public class linkedhashmapextends hashmapimplements map 其也有乙個entry內部類,繼承了 hashmap 的entry 內部類...

JDk原始碼解析之四 Vector原始碼解析

具體的三個屬性 解釋看圖中注釋。vector沒有採取arraylist臨界值擴容的辦法,而是每次不夠的時候,直接根據capacity的值來增加。具體怎麼增加後面會說。vector的構造方法如下。簡單粗暴,如果呼叫無參建構函式,直接就將初始容量設定成了10,最終在右側的構造方法裡,將陣列的長度設定為1...

JDK原始碼解析 ThreadLocal

說明 本文是jdk 1.8版本 1.簡介 threadlocal 又叫做執行緒本地變數,也被稱為執行緒本地儲存。threadlocal 為 變數 在每乙個執行緒中建立 乙個 副本 不是原來變數的引用 每乙個執行緒都會獨自擁有變數副本,而不會相互影響。2.實現方式 1 set 方法,因為執行緒thre...