hashmap 知識點
hashmap是什麼?
hashmap是用來儲存key-value鍵值對的集合類 它具有儲存效率高,查詢速度快的特點。
hashmap的底層實現原理是什麼?
hashmap底層是基於(陣列+鍊錶+紅黑樹)結構來實現的,陣列元素採用node節點來儲存key-value鍵值對的資訊。
hashmap的預設初始容量為16 預設負載因子是0.75 最大容量是2^30
主要方法有put get
1.在put key-value時 如果雜湊表沒有初始化先進行初始化, 再根據key.hashcode計算出hash值 然後通過hash值和陣列長度計算出相對應的陣列下標
2.如果該下標對應位置的元素是null, 則直接將node存入該位置,如果陣列元素不為null 取得鍊錶(紅黑樹)的頭節點的key值 如果頭節點的key等於put的key值 則直接更新該節點的value值
如果不等於 繼續向後查詢 如果鍊錶中存在key值 則做覆蓋 不存在則插入鍊錶的尾部
3.當鍊表節點數量大於8時且陣列長度大於等於64時 改用紅黑樹進行儲存節 當節點數量小於6時改回鍊錶儲存。
4.插入完成後 如果當前節點數size>當前的閾值 則對陣列進行擴容 擴容至當前容量的2倍 擴容後對陣列裡的元素進行重hash
5.例項化hashmap時 建議指定初始容量(kv鍵值對數量 /
0.75
) 這樣可以減少擴容重hash帶來的效能消耗
hashmap 是非執行緒安全的 如需要執行緒安全可以使用 concurrenthashmap
為什麼擴容是根據2的n次冪進行擴容
為了降低hash碰撞的機率
陣列下標的計算方式 是根據node的hash值 和 陣列長度-
1做或運算 而2的n次冪-
1 二級制就是全是1111 和hash值運算的結果 就是取hash值的後n位
只要hash值分布均勻 計算出來的下標也是均勻分布的
為什麼預設負載因子是0.75?
負載因子過大 hash碰撞概率增大 導致鍊錶長度增加 查詢時間成本增加 從而導致效能降低
負載因子過小 會導致空間浪費
通過計算 負載因子為0.75 能夠很好節省時間成本和空間成本 時間和空間的權衡
為什麼執行緒不安全?
1.例如:執行緒a執行put資料操作,已找到需要儲存的陣列位置,且該位置元素為null, 此時執行緒a時間片用完,執行緒b開始執行put資料操作 且兩個執行緒put的資料正好在陣列的同乙個位置,
b執行插入完成,a接著執行完成 結果是執行緒aput的資料會把執行緒bput的資料給覆蓋掉 正確應該兩個執行緒put的資料都存在雜湊表中
2.頭插法 resize時會出現死迴圈 執行緒a b 都對同一鍊錶進行rehash時 執行緒a 取到頭節點m next是節點n 此時執行緒時間片用完 執行緒b 整個rehahs操作執行完後的 鍊錶是 頭節點變成n next 是m
執行緒a 繼續執行 m的next是n n的next又是m 這樣就死迴圈了
為什麼最大容量是為什麼是2的30次冪?
1<<
30 因為int型別的是4個位元組 32位 而最高位用來區分正負數 如果把1左移31位的話 最高位就變成1 了 這個值就成了負數了 所以只能左移30位
jdk1.
7和1.8有什麼區別?
1.底層結構不一樣 1.7使用的陣列+鍊錶 1.8使用的陣列+鍊錶+紅黑樹 (鍊錶長度》
8 時轉紅黑樹儲存)
2.hash衝突時,插入節點方式不同 1.7使用頭插法 1.8使用尾插法 (頭插入 多執行緒同時rehash時會出現死迴圈)
3.hash函式演算法不一樣 1.7節點的hash直接使用key的hashcoe 4次位移 5次異或 1.8 使用key的hashcode 和 hashcode右移16 異或的結果
使hashcode的高位也參與了運算 使元素更加均勻分布
4.擴容順序不同 1.7是在插入資料前進行擴容 1.8是在插入資料後再進行擴容
5.擴容重雜湊後鍊錶節點順序不一樣 1.7會顛倒鍊錶順序 1.8 會保持原來的順序
6.重雜湊時 陣列下標計算方式不一樣 1.7 hash值(擴容後容量-
1) 或 運算 1.8 直接hash&擴容前容量==
0 當前下標 + 擴容前容量值
7.1.7 初始化table 呼叫inflatetable()
1.8 初始化table 放在擴容函式 resize 裡
什麼時候進行resize操作?
有兩種情況會進行resize:1、初始化table;2、在size超過threshold之後進行擴容
節點在轉移的過程中是乙個個節點複製還是一串一串的轉移?
遍歷鍊錶 把擴容後還出於同一下標的節點重新組合成一條鍊錶,再把頭鍊錶放入新的陣列下標中
從原始碼中我們可以看出,擴容時是先找到拆分後處於同乙個桶的節點,將這些節點連線好,然後把頭節點存入桶中即可
擴容演算法(擴容至大於等於n的2的m次冪) 大於閾值(當前容量 * 負載因子) 時擴容
n -=
1 n |= n >>>1;
n |= n >>>2;
n |= n >>>4;
n |= n >>>8;
n |= n >>>16;
鍊錶hash值的計算
key.
hashcode()
^ key.
hashcode()
>>>
16 在計算陣列下標時只用到了hash值的低位 為了使陣列下標更加雜湊 所以把keyhashcode低位跟高位進行異或運算 一般來說陣列長度小於2
^16 所以位移16位
因為使用 & 結果偏向 0 使用 | 結果偏向 1 所以使用^
(異或)
陣列下標的計算 (hash 就是 任意長度的資料對映到有限長度的域上)
hash &
(length -
1) 即 hash % length 根據陣列長度對node的hash值進行取餘 使其雜湊 在陣列內
紅黑樹 紅黑樹是乙個平衡二叉樹 但不是乙個完美的平衡二叉樹 在動態插入保持樹的完美平衡代價太高了 我們希望查詢時間複雜度為logn
1.節點非紅即黑
2.根節點是黑色
3.每個葉子節點(nil)是黑色
4.紅色節點的子節點必須是黑色(不能存在連續兩個紅節點)
5.任一節點到其葉子節點路徑 包含相同的黑色節點數
吊打面試官之HashMap
hashmap的底層資料結構是什麼?jdk1.7和jdk1.7前使用的是陣列,鍊錶 jdk1.8和jdk1.8後使用的是陣列,鍊錶,紅黑樹 hashmap的put方法流程是怎麼樣的?1.先獲取key的hash值 注意 通過key獲取hash值,直接獲取hash值就可以了,但是這裡把key的hash值...
產品經理面試篇 10秒吊打面試官
表面 請簡單介紹下自己。實際 你先出牌,我要看著打。最拽的自我介紹就是 我爸讓我來的!最快的撩妹攻略就是 i m rich!最狠的社會毒打就是 以上均來自真實案例!不過凡是無絕對嘛,既然以上套路都不是100 成功,那麼憑什麼素昧謀面的人有資格告訴你所謂的模板 攻略 注意事項 重點等等?後續內容沒有模...
Redis吊打面試官的經典面試題整理
1 redis為什麼是key,value的,為什麼不是支援sql的?這題第一眼看到有點懵逼 選擇key value的原因 key value簡單粗暴,使用方便?效率更佳?為什麼不支援sql 因為redis的記憶體模型是乙個hashtable,不使用表來儲存資料,也不會預定義或強制要求使用者對redi...