「Java面試」為什么重寫 equals() 就一定要重寫 hashCode() 方法
“為什么重寫 equals() 就一定要重寫 hashCode() 方法?”
一個工作了4年的粉絲,好不容易拿到一個面試機會,結果就被這個問題暴擊了!沒辦法,只能來向我求助了。
經(jīng)常有同學在后臺跟我吐槽,在求職過程中遇到的各種面試難題。
我發(fā)現(xiàn)大部分的問題之前的文章都有分析過,考慮到文章可能太過分散,不方便大家學習,所以我系統(tǒng)整理了一份20萬字的文檔,有需要的Si信我發(fā)送“Mic”領取。
回答這個問題之前,我們先來分析一下這個問題的背景。
問題分析
關于這個問題,首先需要深入了解一下equals這個方法。
這個equals方法是String這個類里面的實現(xiàn)。
從代碼中可以看到,當調(diào)用equals比較兩個對象的時候,會做兩個操作
用==號比較兩個對象的內(nèi)存地址,如果地址相同則返回true
否則,繼續(xù)比較字符串的值,如果兩個字符串的值完全相等,同樣返回true

那equals和hashCode()有什么關系呢?
首先,Java里面任何一個對象都有一個native的hashCode()方法
其次,這個方法在散列集合中會用到,比如HashTable、HashMap這些,當添加元素的時候,需要判斷元素是否存在,而如果用equals效率太低,所以一般是直接用對象的hashCode的值進行取模運算。
如果table中沒有該hashcode值,它就可以直接存進去,不用再進行任何比較了;
如果存在該hashcode值, 就調(diào)用它的equals方法與新元素進行比較,相同的話就不存了,不相同就散列其它的地址,所以這里存在一個沖突解決的問題,這樣一來實際調(diào)用equals方法的次數(shù)就大大降低了。
hashCode的值默認是JVM使用隨機數(shù)來生成的,兩個不同的對象,可能生成的HashCode會相同。
這種情況在Hash表里面就是所謂的哈希沖突,通常會使用鏈表或者線性探測等方式來解決沖突問題。
但是如果兩個完全相同的對象,也就是內(nèi)存地址指向同一個,那么他們的hashCode一定是相同的。
了解了equals和hashCode的關系以后,再來分析這個面試題。
在理論情況下,如果x.equals(y)==true,如果沒有重寫equals方法,那么這兩個對象的內(nèi)存地址是同一個,意味著hashCode必然相等。
但是如果我們只重寫了equals方法,就有可能導致hashCode不相同。
一旦出現(xiàn)這種情況,就導致這個類無法和所有集合類一起工作。
所以,在實際開發(fā)中,約定俗成了一條規(guī)則,重寫equals方法的同時也需要重寫hashCode方法。
高手:
如果只重寫equals方法,不重寫hashCode方法。
就有可能導致a.equals(b)這個表達式成立,但是hashCode卻不同。
那么這個只重寫了equals方法的對象,在使用散列集合進行存儲的時候就會出現(xiàn)問題。
因為散列結合是使用hashCode來計算key的存儲位置,如果存儲兩個完全相同的對象,但是有不同的hashcode就會導致這兩個對象存儲在hash表的不同位置,當我們想根據(jù)這個對象去獲取數(shù)據(jù)的時候,就會出現(xiàn)一個悖論,一個完全相同的對象會在存儲在hash表的兩個位置,造成大家約定俗成的規(guī)則,出現(xiàn)一些不可預料的錯誤。
總結
強調(diào)一遍,基礎很重要,基礎很重要。
不要覺得每天寫CRUD能解決業(yè)務問題就很牛逼了,等你工作了7~8年以后會發(fā)現(xiàn)
對技術體系化的理解和技術底層原理的學習才是自己的核心競爭力。
麻煩觀眾老爺看到最后,覺得本文內(nèi)容不錯的話,請三連支持一下吧~(祝你程序永遠沒有BUG)