hashmap和hashset的理解,關於hashcode和equals。

這只是我的個人筆記,想要看詳細的可以去Java中的equals和hashCode方法詳解java提高篇(二三)-----HashMap


Java中的equals方法和hashCode方法是Object中的,所以每個對象都是有這兩個方法的,有時候我們需要實現特定需求,可能要重寫這兩個方法,今天就來介紹一些這兩個方法的作用。

equals()和hashCode()方法是用來在同一類中做比較用的,尤其是在容器裏如set存放同一類對象時用來判斷放入的對象是否重複。
這裏我們首先要明白一個問題:
          equals()相等的兩個對象,hashcode()一定相等,equals()不相等的兩個對象,卻並不能證明他們的hashcode()不相等。換句話說,equals()方法不相等的兩個對象,hashCode()有可能相等。(我的理解是由於哈希碼在生成的時候產生衝突造成的)
       在這裏hashCode就好比字典裏每個字的索引,equals()好比比較的是字典裏同一個字下的不同詞語。就好像在字典裏查“自”這個字下的兩個詞語“自己”、“自發”,如果用equals()判斷查詢的詞語相等那麼就是同一個詞語,比如equals()比較的兩個詞語都是“自己”,那麼此時hashCode()方法得到的值也肯定相等;如果用equals()方法比較的是“自己”和“自發”這兩個詞語,那麼得到結果是不想等,但是這兩個詞都屬於“自”這個字下的詞語所以在查索引時相同,即:hashCode()相同。如果用equals()比較的是“自己”和“他們”這兩個詞語的話那麼得到的結果也是不同的,此時hashCode() 得到也是不同的。


     反過來:hashcode()不等,一定能推出equals()也不等;hashcode()相等,equals()可能相等,也可能不等。在object類中,hashcode()方法是本地方法,返回的是對象的地址值,而object類中的equals()方法比較的也是兩個對象的地址值,如果equals()相等,說明兩個對象地址值也相等,當然hashcode() 也就相等了;


同時hash算法對於查找元素提供了很高的效率
如果想查找一個集合中是否包含有某個對象,大概的程序代碼怎樣寫呢?
你通常是逐一取出每個元素與要查找的對象進行比較,當發現某個元素與要查找的對象進行equals方法比較的結果相等時,則停止繼續查找並返回肯定的信息,否則,返回否定的信息,如果一個集合中有很多個元素,比如有一萬個元素,並且沒有包含要查找的對象時,則意味着你的程序需要從集合中取出一萬個元素進行逐一比較才能得到結論。


有人發明了一種哈希算法來提高從集合中查找元素的效率,這種方式將集合分成若干個存儲區域,每個對象可以計算出一個哈希碼,可以將哈希碼分組(使用不同的hash函數來計算的),每組分別對應某個存儲區域,根據一個對象的哈希嗎就可以確定該對象應該存儲在哪個區域HashSet就是採用哈希算法存取對象的集合,它內部採用對某個數字n進行取餘(這種的hash函數是最簡單的)的方式對哈希碼進行分組和劃分對象的存儲區域;Object類中定義了一個hashCode()方法來返回每個Java對象的哈希碼,當從HashSet集合中查找某個對象時,Java系統首先調用對象的hashCode()方法獲得該對象的哈希碼錶,然後根據哈希嗎找到相應的存儲區域,最後取得該存儲區域內的每個元素與該對象進行equals方法比較;這樣就不用遍歷集合中的所有元素就可以得到結論,可見,HashSet集合具有很好的對象檢索性能,但是,HashSet集合存儲對象的效率相對要低些,因爲向HashSet集合中添加一個對象時,要先計算出對象的哈希碼和根據這個哈希碼確定對象在集合中的存放位置爲了保證一個類的實例對象能在HashSet正常存儲,要求這個類的兩個實例對象用equals()方法比較的結果相等時,他們的哈希碼也必須相等;也就是說,如果obj1.equals(obj2)的結果爲true,那麼以下表達式的結果也要爲true:
obj1.hashCode() == obj2.hashCode()
換句話說:當我們重寫一個對象的equals方法,就必須重寫他的hashCode方法,不過不重寫他的hashCode方法的話,Object對象中的hashCode方法始終返回的是一個對象的hash地址,而這個地址是永遠不相等的。所以這時候即使是重寫了equals方法,也不會有特定的效果的,因爲hashCode方法如果都不想等的話,就不會調用equals方法進行比較了,所以沒有意義了。


如果一個類的hashCode()方法沒有遵循上述要求,那麼,當這個類的兩個實例對象用equals()方法比較的結果相等時,他們本來應該無法被同時存儲進set集合中,但是,如果將他們存儲進HashSet集合中時,由於他們的hashCode()方法的返回值不同(Object中的hashCode方法返回值是永遠不同的),第二個對象首先按照哈希碼計算可能被放進與第一個對象不同的區域中,這樣,它就不可能與第一個對象進行equals方法比較了,也就可能被存儲進HashSet集合中了,Object類中的hashCode()方法不能滿足對象被存入到HashSet中的要求,因爲它的返回值是通過對象的內存地址推算出來的,同一個對象在程序運行期間的任何時候返回的哈希值都是始終不變的,所以,只要是兩個不同的實例對象,即使他們的equals方法比較結果相等,他們默認的hashCode方法的返回值是不同的。



HashSet:往HashSet中添加元素的時候,會首先調用該元素的HashCode方法,得到該元素的哈希值從而計算出存放關係,若該位置已經有值,則比較equals方法,若返回true,視爲相同元素,爲false,則添加元素。

HashMap:影響性能的因素,初始容量和加載因子。同樣也會通過HashCode和equals方法判斷相應情況作出決定。


發佈了80 篇原創文章 · 獲贊 25 · 訪問量 13萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章