Map的key是否可重復


我們都知道Map的一大特性是key唯一不可重復,可是真的是這樣的嗎?

我們來試驗一下:

 

 

 運行結果:

  

 

 我們可以看到在map里有兩個同樣的person作為key,打破了map的key不可重復的特性。

我們平時操作map一般不會出現這樣的結果,怎樣操作會出現上述的現象呢?

1、首先有前提條件,作為key的person必須重寫hashCode與equals這兩個方法保證我們在改變person的屬性之后,該person的hash值發生變化。

2、其次是我們在map中put一個以person對象作為key的元素,然后我們修改該person對象的某一個屬性,再次把該person對象作為key值put到map中,就得到了上述結果。

為什么會出現上述的問題呢?

  我們要明白map的數據結構以及數據是如何存儲到map中的

  JDK1.7 HashMap是數組+鏈表的結構

  JDK8之后HashMap是數組+鏈表+紅黑樹的結構

    tips:當然這里我們就不過多的討論7與8結構的區別

  我們在put一個元素的時候,(其余邏輯省略,這里只關注元素如何定位到數組的桶位置),先拿到key對象的hash值h1,h1無符號右移16位得到h2,

  再把h1與h2進行異或運算得到h3,h3與數組的(length-1)進行與運算得到元素在數組上的最終位置

    

    tips:如果數組長度較小的時候(大多數情況下map的長度不大),key產生的hash值如果高位變化較大很大,而地位變化很小時,

    如果直接拿key的hash值與上(length-1)很容易產生hash沖突,所以無符號右移16位在異或低16位使得高混亂區域與低混亂區域做一個中和,提高hash高低位的一個隨機性,減少hash沖突

上面我們講述了map是如何把元素放入到數組中的,我們再回到上面的問題,第一次把person作為key放入map之后,修改了person的name屬性之后,person的hash值發生變化,從而計算出的

桶位置也隨之而改變(大概率會改變,不是絕對的)再次put到map中就得到兩個相同key值的map。

 

那么在生產應用中我們要避免使用類似於person這樣的對象作為key值存儲在Map中,可以使用Integer、String這樣一些不可變的對象來作為key就可以避免上述情況的發生。

  插一句題外話,HashSet是無序不可重復的,它其實也存在上面的情況,原因很簡單HashSet的底層就是HashMap

    附HashSet相關代碼截圖

  

 

 

 

  

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM