日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

面试再也不怕问到HashMap(二)

發布時間:2024/9/30 编程问答 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 面试再也不怕问到HashMap(二) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

詳細源碼解析查看面試再也不怕問到HashMap(一)

HashMap干貨總結

1,可以用null做為key和value
2,capacity和load factor影響性能
3,線程不安全
4,HashMap不能保證隨著時間的推移Map中的元素次序是不變的。
5,迭代時并發更改了map,則會拋出ConcurrentModificationException
6,當同一個bucket上元素擁擠(默認值為8)時,會將列表轉變成紅黑樹來提高查詢性能,縮減時(默認值為6)會恢復為鏈表。紅黑樹查找位置時折半查找效率高于鏈表,而刪除操作效率低于鏈表。
7,hash(key)核心hash算法,在長度為2的冪前提下,hash值高位下移16位,參與取模,降低碰撞,另外取模部分利用2的冪減1來做&操作提高了性能。
8,鏈表狀態下碰撞元素加入時是放入鏈表尾部,因為它認為最近放入的元素可能最容易被使用。
9,繼承Serializable接口,可是字段使用transient修飾,比如table,entrySet。原因是hashcode操作依賴jvm所處的環境因素,不同環境可能有不同的hash值,做成存儲的內容既是序列化也無法通用.所以hashmap自己實現了writeObject和readObject,這里就需要知道java在序列化和反序列化一個類時是先調用writeObject和readObject,如果沒有默認調用的是ObjectOutputStream的defaultWriteObject以及ObjectInputStream的defaultReadObject方法。
10,樹中當兩個節點的hash一樣,會利用compareTo方法比較,如果還是相同,就使用identityHashCode進行比較。

JDK1.7和1.8的HashMap的不同點

(1)在位于同一個bucket時,JDK1.8是使用的尾插法,能夠避免出現逆序且鏈表死循環的問題。JDK1.7是單鏈表進行的縱向延伸,采用頭插法能夠提高插入的效率,但是也會容易出現逆序且環形鏈表死循環問題。

(2)擴容后數據存儲位置的計算方式也不一樣:

? ? ? ?在JDK1.7的時候是直接用hash值和擴容后容量的二進制數進行&即hash值 & length-1 。
? ? ? ?而在JDK1.8的時候是 原索引位置+擴容的大小值=新的位置。這種方式只需要判斷Hash值的新增參與運算的位是0還是1就可迅速計算出了擴容后的索引位置。

(3)JDK1.7的時候使用的是數組+ 單鏈表的數據結構。但是在JDK1.8及之后,使用的是數組+鏈表+紅黑樹的數據結構(當鏈表的深度達到8的時候,也就是默認閾值,就會自動擴容把鏈表轉成紅黑樹的數據結構來把時間復雜度從O(N)變成O(logN),提高了查找效率)。

hashMap的長度為什么一定是2的次冪?

  • 會使得在數組中位置即索引更加均勻

    ? ? ? ?我們看到,上面的&運算,高位是不會對結果產生影響的(hash函數采用各種位運算可能也是為了使得低位更加散列)。我們只關注低位bit,如果低位全部為1,那么對于h低位部分來說,任何一位的變化都會對結果產生影響,也就是說,要得到index=21這個存儲位置,h的低位只有這一種組合。這也是數組長度設計為必須為2的次冪的原因。

    ? ? ? ?如果不是2的次冪,也就是低位不是全為1此時,要使得index=21,h的低位部分不再具有唯一性了,哈希沖突的幾率會變的更大,同時,index對應的這個bit位無論如何不會等于1了,而對應的那些數組位置也就被白白浪費了。

  • 擴容時便于快速計算新的存儲位置(java8中采用的索引的新計算方式)

    只需要看看原來的hash值新增的那個bit是1還是0就好了,是0的話索引沒變,是1的話索引變成“原索引+oldCap。

  • HashMap和HashTable的區別

    • HashMap可以存儲null值(value)和null鍵(key),而Hashtable不行。
    • HashMap是非線程安全的,而Hashtable是線程安全的,這也意味著性能也會差點。Java 5提供了ConcurrentHashMap,它是HashTable的替代,比HashTable的擴展性更好。

    HashMap為什么是線程不安全的?

    HashMap 在并發時可能出現的問題主要是兩方面:

    • put的時候導致的多線程數據不一致

    ? ? ? ?比如有兩個線程A和B,首先A希望插入一個key-value對到HashMap中,首先計算記錄所要落到的 hash桶的索引坐標,然后獲取到該桶里面的鏈表頭結點,此時線程A的時間片用完了,而此時線程B被調度得以執行,和線程A一樣執行,只不過線程B成功將記錄插到了桶里面,假設線程A插入的記錄計算出來的 hash桶索引和線程B要插入的記錄計算出來的 hash桶索引是一樣的,那么當線程B成功插入之后,線程A再次被調度運行時,它依然持有過期的鏈表頭但是它對此一無所知,以至于它認為它應該這樣做,如此一來就覆蓋了線程B插入的記錄,這樣線程B插入的記錄就憑空消失了,造成了數據不一致的行為。

    • resize而引起死循環

    ? ? ? ?這種情況發生在HashMap自動擴容時,當2個線程同時檢測到元素個數超過 數組大小 × 負載因子。此時2個線程會在put()方法中調用了resize(),兩個線程同時修改一個鏈表結構會產生一個循環鏈表(JDK1.7中,會出現resize前后元素順序倒置的情況)。接下來再想通過get()獲取某一個元素,就會出現死循環。

    親自動手驗證hashMap的實驗
    hashMap注釋翻譯

    總結

    以上是生活随笔為你收集整理的面试再也不怕问到HashMap(二)的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。