09.16 通過HashMap的源碼來理解重寫equals和hashcode

通過HashMap的源碼來理解重寫equals和hashcode

這篇文章主要通過HashMap#put的源碼來聊聊為什麼需要同時重寫hashcode和equals。

這是在某個企業面試的時候,感覺自己說的不夠清楚,這裡地方再總結下,希望對大家有所幫助。

額外補充一句,程序猿要晉級到工程師或者架構師,該從底層去探究的東西還是要耐心結合源碼進行分析,不是僅僅看別人的總結和理論知識點就可以了,需要自己結合源碼進行理解、鞏固、實踐。

day day up , never give up !


為什麼

對於散列結構的數據類型,比如HashMap或者HashSet這些數據類型。若我們從業務上判定對象是表示的同一個事物,那麼需要重寫equals和hashcode,來保證在內存中不同的對象在業務上是一致的。

上面這話有些繞。業務上相同的但是代碼層面不相同的對象,當需要hash結構進行保存的時候,就需要重寫hashcode和equals方法了。

默認情況下

  • equals是繼承自Object父類的,其中通過==進行對比。
  • hashcode也是繼承自Object父類的,通過native方法進行hashcode計算。

Hashmap源碼

以下是JDK8的hashmap的源碼,對此我想吐槽下:寫的真是精煉,能一行寫的,絕不兩行寫,最開始看的時候,變量哪裡賦值都看了半天,實際項目編碼中個人還是不推薦這種精煉的寫法的,代碼寫出來是給大部分人讀的以及後續維護的,所以性能一致或者差不多的情況下 ”可讀性才是最重要的“

通過HashMap的源碼來理解重寫equals和hashcode

上述代碼是JDK8關於HashMap的put的底層源碼,有部分省略的地方,請注意查看”關鍵1”和“關鍵2”

上述代碼關鍵1處的代碼是:

通過HashMap的源碼來理解重寫equals和hashcode

其中p表示的是數組中根據hashcode運算後找出的某個具體的數組值,簡單來講就是鏈表第一個值。

其中e是exsiting的縮寫,表示已經存在的,該值需要在最後做判定後插入。


說回關鍵1處的代碼:源碼編寫者應該是有意的通過 && 進行分割。關於&&和&的區別,我們下篇文章再談,很有意思的一個知識點。

  • 上面的判定是p.hash == hash這個很明顯是判定hash值。重寫hashcode的原因在這裡。
  • 下面的判定是(k = p.key) == key 和 (key != null && key.equals(k)),要求滿足其中1個就行了。
  • 前者通過==直接判定內存地址,這個判定肯定同一個對象。因為==我們是沒有辦法重寫的。
  • 後者是判定的equals,這個判定是標題提到的需要重寫的equals方法。重寫eqauls的原因在這裡。

關鍵代碼2處的代碼也是類似的思路,請讀者自行理解,不再贅述。

總結

hashcode被重寫是因為保證同一個業務對象在數組尋址時,落到同一個節點和對鏈表第一個節點進行判定。

eqauls被重寫是因為需要在鏈表中尋找該對象是否已經存在,來判定替換或者插入。


分享到:


相關文章: