在Java 8 以前,HashMap和其餘基於map的類都是經過鏈地址法解決衝突,它們使用單向鏈表來存儲相同索引值的元素。在最壞的狀況下,這種方式會將HashMap的get方法的性能從O(1)下降到O(n)。爲了解決在頻繁衝突時hashmap性能下降的問題,Java 8中使用平衡樹來替代鏈表存儲衝突的元素。這意味着咱們能夠將最壞狀況下的性能從O(n)提升到O(logn)。
在Java 8中使用常量TREEIFY_THRESHOLD來控制是否切換到平衡樹來存儲。目前,這個常量值是8,這意味着當有超過8個元素的索引同樣時,HashMap會使用樹來存儲它們。
這一改變是爲了繼續優化經常使用類。你們可能還記得在Java 7中爲了優化經常使用類對ArrayList和HashMap採用了延遲加載的機制,在有元素加入以前不會分配內存,這會減小空的鏈表和HashMap佔用的內存。
這一動態的特性使得HashMap一開始使用鏈表,並在衝突的元素數量超過指定值時用平衡二叉樹替換鏈表。不過這一特性在全部基於hash table的類中並無,例如Hashtable和WeakHashMap。
目前,只有ConcurrentHashMap,LinkedHashMap和HashMap會在頻繁衝突的狀況下使用平衡樹。算法
何時會產生衝突
HashMap中調用hashCode()方法來計算hashCode。
因爲在Java中兩個不一樣的對象可能有同樣的hashCode,因此不一樣的鍵可能有同樣hashCode,從而致使衝突的產生。性能
總結
HashMap在處理衝突時使用鏈表存儲相同索引的元素。
從Java 8開始,HashMap,ConcurrentHashMap和LinkedHashMap在處理頻繁衝突時將使用平衡樹來代替鏈表,當同一hash桶中的元素數量超過特定的值便會由鏈表切換到平衡樹,這會將get()方法的性能從O(n)提升到O(logn)。
當從鏈表切換到平衡樹時,HashMap迭代的順序將會改變。不過這並不會形成什麼問題,由於HashMap並無對迭代的順序提供任何保證。
從Java 1中就存在的Hashtable類爲了保證迭代順序不變,即使在頻繁衝突的狀況下也不會使用平衡樹。這一決定是爲了避免破壞某些較老的須要依賴於Hashtable迭代順序的Java應用。
除了Hashtable以外,WeakHashMap和IdentityHashMap也不會在頻繁衝突的狀況下使用平衡樹。
使用HashMap之因此會產生衝突是由於使用了鍵對象的hashCode()方法,而equals()和hashCode()方法不保證不一樣對象的hashCode是不一樣的。須要記住的是,相同對象的hashCode必定是相同的,但相同的hashCode不必定是相同的對象。
在HashTable和HashMap中,衝突的產生是因爲不一樣對象的hashCode()方法返回了同樣的值。
以上就是Java中HashMap如何處理衝突。這種方法被稱爲鏈地址法,由於使用鏈表存儲同一桶內的元素。一般狀況HashMap,HashSet,LinkedHashSet,LinkedHashMap,ConcurrentHashMap,HashTable,IdentityHashMap和WeakHashMap均採用這種方法處理衝突。優化
從JDK 8開始,HashMap,LinkedHashMap和ConcurrentHashMap爲了提高性能,在頻繁衝突的時候使用平衡樹來替代鏈表。由於HashSet內部使用了HashMap,LinkedHashSet內部使用了LinkedHashMap,因此他們的性能也會獲得提高。.net
HashMap的快速高效,使其使用很是普遍。其原理是,調用hashCode()和equals()方法,並對hashcode進行必定的哈希運算獲得相應value的位置信息,將其分到不一樣的桶裏。桶的數量通常會比所承載的實際鍵值對多。當經過key進行查找的時候,每每可以在常數時間內找到該value。code
可是,當某種針對key的hashcode的哈希運算獲得的位置信息重複了以後,就發生了哈希碰撞。這會對HashMap的性能產生災難性的影響。對象
在Java 8 以前, 若是發生碰撞每每是將該value直接連接到該位置的其餘全部value的末尾,即相互碰撞的全部value造成一個鏈表。blog
所以,在最壞狀況下,HashMap的查找時間複雜度將退化到O(n).排序
可是在Java 8 中,該碰撞後的處理進行了改進。當一個位置所在的衝突過多時,存儲的value將造成一個排序二叉樹,排序依據爲key的hashcode。索引
則,在最壞狀況下,HashMap的查找時間複雜度將從O(1)退化到O(logn)。內存
雖然是一個小小的改進,但意義重大:
一、O(n)到O(logn)的時間開銷。
二、若是惡意程序知道咱們用的是Hash算法,則在純鏈表狀況下,它可以發送大量請求致使哈希碰撞,而後不停訪問這些key致使HashMap忙於進行線性查找,最終陷入癱瘓,即造成了拒絕服務攻擊(DoS)。————————————————版權聲明:本文爲CSDN博主「buder得兒得兒以得兒以得兒得兒」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處連接及本聲明。原文連接:https://blog.csdn.net/cpcpcp123/article/details/52744331