hashmap原始碼面試分析
rudynan發表於2020-11-04
HashMap原始碼問題解析
- 問: 說一說對hash的理解
答: hash是對任意長度的輸入輸出為相同長度的輸出
- 問: hash演算法的問題
答: hash衝突問題
- 問: hash衝突是否可以避免
答: 不可以避免,只能儘量規避
- 問: 優秀的hash演算法有什麼特性
答: 1. 任何微小的變化hash的結果都不相同
2. hash不可逆
3. 長字串的hash效率要高
4. hash值儘量雜湊平均
5. 相同的值hash值相同
- 問: hashmap的資料結構
答: 以1.8為例 陣列+連結串列+紅黑樹 資料儲存在node物件中,node中有key value next hash等欄位
- 問: 雜湊表的初始長度是多長
答: 預設是16
- 問: 雜湊表是什麼時候建立
答: 第一次put的時候建立(懶載入)
- 問: 預設的負載因子是多少,負載因子的作用
答: 空參構造建立的hashmap的負載因子是0.75,作用是當node數量大於陣列長度的0.75的時候進行resize擴容
- 問: 連結串列轉化紅黑樹需要什麼條件
答: 需要兩個條件 連結串列長度大於等於7並且陣列的長度大於等於64才進行樹化
- 問node物件的hash值是怎麼得來的,為什麼這麼操作
答: 是根據key的hashcode值在與key的hashcode的高16位異或操作得來的,是為了在陣列中分佈的更加隨機均勻,因為hashmap的資料計算陣列下標的方法是(tab.length-1)&hash,tab.length大部分情況下小於2^16也就是25536(規則表明tab.length必須是2的次方數) 所以大部分情況下是hash的低16位參與運算,為了讓hash更加隨機均勻,多一次與key的hashcode異或運算來加強hash值的隨機分佈,讓hashcode沒一位都參與到運算中
- 問: hashmap put方法的詳細流程
答: key經過定址查到在陣列中的下標
1. 如果陣列下標為null直接存入node
2. 如果不為空比較值 相同覆蓋 如果是樹則按紅黑樹規則放入 如果不是樹 進行尾插連結串列長度大於等於7並且陣列長度大於64轉樹 長度超過閾值resize
- 問: 紅黑樹的原則
答: 1. 葉子節點到根節點的路徑黑色節點數量一致(黑高)
2. 葉子節點都是黑色的
3. 不能有兩個紅色的節點相連
4. 根節點一定是黑色的
5. 插入的節點一定是紅色的(紅插)
- 問: jdk1.8hashmap為什麼引入紅黑樹
答: 因為連結串列太長的話會導致查詢效率降低hash的目的是儘量實現o(1)的,連結定址很慢
- 問: hashmap什麼時候會觸發擴容
答: put操作的時候,有個欄位記錄資料量當大於擴容閾值的時候擴容
- 問: hashmap怎麼擴容
答: 陣列長度一定是2的次方數,每次擴容是原先長度左移一位<<1
- 問: 老陣列的資料怎麼遷移到新陣列中
答: 1. hash未衝突的直接根據新的陣列長度計算放入即可
2. 如果已經成紅黑樹
3. 已經是連結串列未成樹會hash&舊陣列長度(oldcap) 等於0的放低鏈 不等於的放高鏈 低鏈的放原來的index 高鏈放原來的index+oldlength的位置
解釋:在hashmap定址演算法計算得出(hash&(length-1)) 一條連結串列的資料肯定會分成兩個連結串列 位置一個是原index 另一個是原index+oldlength
原先的length長度為16 二進位制為10000 那麼length就是16-1 =15(1111)就是hash&1111 以第15個桶為例,那麼hash的值就可能是01111或者11111
擴容後length變為32 二進位制為100000 hash&11111 那麼如果15這個桶位置原先hash是01111的node就放在他原先的15的這個位置,hash為11111的就放在
32這個桶的位置
01111 & 10000 = 0 這個放15這個位置
11111 & 10000 != 0 放32 15+16 = 31這個位置