java中hashcode和equals方法的關係

原文鏈接:https://blog.csdn.net/whuslei/article/details/6686612

Q1:爲什麼要重寫equals方法?
在java中new出來的對象obj1,obj2即使是內容完全相同,但在內存中的地址不一樣,也就是在heap上分配了兩份內存。有時候我們必須比較對象是否已存在,比如HashSet裏的值是不能重複的。那怎麼判斷對象是否一樣呢?調用equals方法。比如 obj1!=null && !obj1.eqauls(obj2)。

Q2:如果DO中沒有寫equals方法,那結果是什麼?
java中任何對象都是Object的子類。通過編譯java字節碼文件時加入"invokespecial java.lang.Object()"來自動引入Object類。如果DO中沒有寫equals方法,則調用時會調用Object的equals方法,默認就是直接比對兩個對象的地址是否一樣了,即this == obj。

Q3:平時使用HashMap或者HashSet好像也沒寫過equals方法呀,什麼時候需要寫呢?
由於平時都是用String、Integer、Double等類作爲key,而這些類中都已經重寫好了equals和hashCode方法。如果需要將某個DO作爲Key,且將其內容作爲"是否重複"的標準(而不是按內存地址比較),則需要自己重寫這兩個方法。

Q4:如果只重寫equals而不重寫hashCode,有什麼問題?
像HashMap這種集合類,原本有兩種做法:
a) 首先是通過eqauls判斷key是否存在,然後再根據hash值定位到具體的區域上。
b) 首先根據hash值定位到某個區域上,然後再在區域內進行equals判斷
這裏的區域其實就是指HashMap的鏈表。方法a顯然不妥,它需要在插入前和元素內的所有元素都比較一次,性能很差。所以HashMap採用的是方法b,先用hash值定位到某個table[i]上,然後再遍歷鏈表,調用equals方法判斷元素是否已存在! 回到問題上,如果不重寫hashcode,假如obj1被放在table[i]上,根據內存地址obj2很可能被定位到table[j]上,obj2根本沒機會和obj1進行equals比較了,即時他們是相同的!即違背了Set無重複元素!
     
 jdk規範中說道,如果要實現自己的equals()方法,則也需要實現相應的hashCode()方法。爲什麼?這是爲了避免在HashMap等hash類使用時出現異常。當然,jdk也不會強制要求你這麼做,它只是告訴你,不這麼做,出了什麼問題,別找它!

      所以,一般來講,A.equals(B) == true 則可以推出 A.hashCode() == B.hashCode(),但是反過來就不行了。因爲,兩者的hashCode相同並不能推出他們的內容相同!這是一個原則問題。

      比如 A.hashCode() == B.hashCode(),但是,A.equals(B) == false ,那麼放入HashMap中時就會發生衝突。比如用拉鍊法,則A 和 B將會映射到同一個鏈表中。但是,匹配的時候,C.hashCode() 和A、B的相等,C的內容和B相等,那麼最後匹配上的就是B,而不會是A!
————————————————
版權聲明:本文爲CSDN博主「whuslei」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/whuslei/article/details/6686612

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章