hashmap底層是陣列,稱為雜湊桶,儲存結構:jdk7是陣列+鍊錶,jdk8 是陣列+鍊錶/紅黑樹。
1、鍊錶插入方式的不同
在1.7之前,鍊錶元素的插入採用的是頭插法,也就是說,當有新結點進來時,會在插入在鍊錶的頭部。很明顯,由於不用遍歷鍊錶,這種插入方式的效率是更高的。但是1.8之後,因為當結點插入的時候,本身就要為了判斷元素的個數而遍歷鍊錶(看看是否達到了樹化的閾值),所以就可以搭乙個順風車,在遍歷完之後,把結點插入到鍊錶尾部,即採用的尾插法。這種方式也解決了多執行緒下可能引發的死鎖問題。因為頭插法的鍊錶在擴容移動時,會被逆序,即後插入的先被處理,如果這個時候有另一線程進行get操作,就有可能引發死鎖。
2、rehash的方式不同(n為陣列長度)
陣列擴容了,key的下標需要重新通過雜湊計算。在1.7之前,採用的是按照之前的方式全部重新計算一遍,這樣很明顯會比較耗費時間。而1.8之後,採用了非常巧妙的一種方式。我們發現,擴容過後,進行與運算的(n - 1),本質上就是把最低的0位變為1而已,比如原來是(0011 1111)就會變為(0111 1111)。那麼同乙份hash值,經過這2個不同的(n - 1)的與運算結果,是有一些關聯的。由於我們的(n-1)就是前面多了乙個1,所以原來的hash值經過該運算,和原結果相比,只會有2種結果,要麼原hash值對應的那個位置是上原本就算0,那麼與運算的結果不變,要麼原來是1,現在就發生了變化。舉個例子:
也就是講,重新計算後的元素,要麼就在原來的位置,要麼就會在乙個新位置這兩種選擇。而這個新位置,從進製中也可以明顯得看出,就是在前面多了乙個1而已,也就是在原基礎上加上了2n(這裡的n都是指原來的n),這個2n剛好也是原來的容量,所以說,元素新的位置,要麼不變,要麼就在(原位置+原容量)這個索引處。而究竟是哪乙個,完全就由hash中權值為2n的這個位決定,而這位的數字,在概率上來說,也是隨機的,也就是大家都是50%的概率,這樣也很好得減小了hash碰撞的概率。
3、插入時機不同
1.7之前是擴容後再插入新的資料
,並且不會先計算插入值的雜湊值,最後單獨算。
1.8之後是先插入再擴容
,插入的值和大家一起計算新的雜湊值。
HashMap在jdk7和jdk8中的實現原理
hashmap在jdk7中實現原理 hashmap map new hashmap 1.在例項化以後,底層建立了乙個長度為16的一維陣列entry table 2.在可能執行多次put後 map.put key1,value1 首先,呼叫key1所在類的hashcode 計算出key1的雜湊值,此雜...
JDK7與JDK8中HashMap的實現的區別
hashmap底層維護乙個陣列,陣列中的每一項都是乙個entry transient entry table 我們向 hashmap 中所放置的物件實際上是儲存在該陣列當中 而map中的key,value則以entry的形式存放在陣列中 static class entryimplements ma...
JDK7 與 JDK8 中 HashMap 的實現
jdk7中的hashmap hashmap底層維護乙個陣列,陣列中的每一項都是乙個entry transient entry table 我們向 hashmap 中所放置的物件實際上是儲存在該陣列當中 而map中的key,value則以entry的形式存放在陣列中 static class entr...