hashCode方法與HashSet類
HashSet就是采用哈希算法存取對象的集合,它內部采用對某個數字n進行取余的方式對哈希碼進行分組和劃分對象的存儲區域,Object類中定義了一個hashCode()方法來返回每個Java對象的哈希碼,當從HashSet集合中查找某個對象時,Java系統首先調用對象的hashCode()方法獲得該對象的哈希嗎,然后根據哈希嗎找到相應的存儲區域,最后取出該存儲區域內的每個元素對該對象進行equals方法比較,這樣不用遍歷集合中的所有元素就可以得到結論。可見,HashSet集合具有很好的對象檢索性能,但是,HashSet集合存儲對象的效率相對要低些,因為向HashSet集合添加一個對象時,要先計算出對象的哈希碼和根據這一個哈希碼確定對象在集合中的存放位置。
為了保證一個類的實例對象能在HashSet正常存儲,要求這個類的兩個實例對象用equals()方法比較的結果相等時,它們的哈希碼也必須相等,也就是說,如果obj1.equals(obj2)的結果為true,那么一下表達式的結果頁要為true。
obj1.hashCode() == obj2.hashCode()
如果一個類的hashCode()方法沒有遵循上述要求,那么,當這個的兩個實例對象用equals()方法比較的結果相等時,它們本來應該無法同時存儲進Set集合中,但是,如果將它們存儲進HashSet集合中時,由于它們的hashCode()方法的返回值不同,第二個對象首先按哈希碼計算可能會被放進與第一個對象不同的區域中,這樣,它就不可能與第一個對象進行equals方法比較了,也就可能被存儲進HashSet集合中了。Object類的hashCode()方法不能滿足對象被存入到HashSet中的要求,因為它的返回值是通過對象的內存地址推算出來的,同一個對象在程序運行期間的任何時候返回的哈希值都是始終不變的,所以,只要是兩個不同的實例對象,即使它們的equals方法比較結果相等,它們默認的hashCode方法的返回值是不同的。
只有類的實例對象被采用哈希算法進行存儲和檢索時,這個類才需要按要求覆蓋hashCode方法。即使程序可能暫時不會用到當前類的hashCode方法,但是為它提供一個hashCode方法也不會有什么不好,沒準以后什么時候又用到這個方法了,所以,通常要求hashCode方法和equals方法一并被同事覆蓋。
提示:
(1)通常來說,一個類的兩個實例對象用equals()方法比較的結果相等時,它們的哈希碼也必須相等,但反之則不成立,即euqlas方法比較結果不相等的對象可以有相同的哈希碼,或者說哈希碼相同的兩個對象的equals方法比較的結果可以不等,例如,字符串“BB”和"Aa"的euqals方法比較結果肯定不相等,但它們的hashCode方法返回值卻相等。
(2)當一個對象被存儲進HashSet集合中以后,就不能修改這個對象中的那些參與計算哈希值的字段了,否則,對象修改后的哈希值與最初存儲進HashSet集合中時的哈希值就不同了,在這種情況下,即使在cantains方法使用該對象的當前引用作為的參數去HashSet集合中檢索對象,也將返回找不到對象的結果。這也會導致從HashSet集合中單獨刪除當前對象,從而造成內存泄露。