HashCode跟Equals的使用

總的來說,Java中的集合(Collection)有兩類,一類是List,再有一類是Set。?

你知道它們的區(qū)別嗎?前者集合內的元素是有序的,元素可以重復;后者元素無序,但元素不可重復。?

那么這里就有一個比較嚴重的問題了:要想保證元素不重復,可兩個元素是否重復應該依據(jù)什么來判斷呢??

這就是Object.equals方法了。但是,如果每增加一個元素就檢查一次,那么當元素很多時,后添加到集合中的元素比較的次數(shù)就非常多了。?

也就是說,如果集合中現(xiàn)在已經(jīng)有1000個元素,那么第1001個元素加入集合時,它就要調用1000次equals方法。這顯然會大大降低效率。????

于是,Java采用了哈希表的原理。哈希(Hash)實際上是個人名,由于他提出一哈希算法的概念,所以就以他的名字命名了。?

哈希算法也稱為散列算法,是將數(shù)據(jù)依特定算法直接指定到一個地址上。如果詳細講解哈希算法,那需要更多的文章篇幅,我在這里就不介紹了。?

初學者可以這樣理解,hashCode方法實際上返回的就是對象存儲的物理地址(實際可能并不是)。???

這樣一來,當集合要添加新的元素時,先調用這個元素的hashCode方法,就一下子能定位到它應該放置的物理位置上。?

如果這個位置上沒有元素,它就可以直接存儲在這個位置上,不用再進行任何比較了;如果這個位置上已經(jīng)有元素了,?

就調用它的equals方法與新元素進行比較,相同的話就不存了,不相同就散列其它的地址。?

所以這里存在一個沖突解決的問題。這樣一來實際調用equals方法的次數(shù)就大大降低了,幾乎只需要一兩次。


所以,Java對于eqauls方法和hashCode方法是這樣規(guī)定的:?

1、如果兩個對象相同,那么它們的hashCode值一定要相同;2、如果兩個對象的hashCode相同,它們并不一定相同???? 上面說的對象相同指的是用eqauls方法比較。???

你當然可以不按要求去做了,但你會發(fā)現(xiàn),相同的對象可以出現(xiàn)在Set集合中。同時,增加新元素的效率會大大下降。

根據(jù)官方文檔的定義,我們可以抽出成以下幾個關鍵點:

1、hashCode的存在主要是用于查找的快捷性,如Hashtable,HashMap等,hashCode是用來在散列存儲結構中確定對象的存儲地址的;

2、如果兩個對象相同,就是適用于equals(Java.lang.Object) 方法,那么這兩個對象的hashCode一定要相同;

3、如果對象的equals方法被重寫,那么對象的hashCode也盡量重寫,并且產生hashCode使用的對象,一定要和equals方法中使用的一致,否則就會違反上面提到的第2點;

4、兩個對象的hashCode相同,并不一定表示兩個對象就相同,也就是不一定適用于equals(java.lang.Object) 方法,只能夠說明這兩個對象在散列存儲結構中,如Hashtable,他們“存放在同一個籃子里”。

再歸納一下就是hashCode是用于查找使用的,而equals是用于比較兩個對象的是否相等的。

public?class?HashTest?{??

private?int?i;??


public?int?getI()?{??

return?i;??

????}??


public?void?setI(int?i)?{??

this.i?=?i;??

????}??


public?int?hashCode()?{??

return?i?%?10;??

????}??


public?final?static?void?main(String[]?args)?{??

HashTest?a?=new?HashTest();??

HashTest?b?=new?HashTest();??

a.setI(1);??

b.setI(1);??

Set?set?=new?HashSet<HashTest>();??

????????set.add(a);??

????????set.add(b);??

????????System.out.println(a.hashCode()?==?b.hashCode());??

????????System.out.println(a.equals(b));??

????????System.out.println(set);??

????}?

返回結果就是:

true??

false??

[com.ubs.sae.test.HashTest@1,?com.ubs.sae.test.HashTest@1]

只是重寫了hashCode方法,從上面的結果可以看出,雖然兩個對象的hashCode相等,但是實際上兩個對象并不是相等;,我們沒有重寫equals方法,那么就會調用object默認的equals方法,是比較兩個對象的引用是不是相同,顯示這是兩個不同的對象,兩個對象的引用肯定是不定的。這里我們將生成的對象放到了HashSet中,而HashSet中只能夠存放唯一的對象,也就是相同的(適用于equals方法)的對象只會存放一個,但是這里實際上是兩個對象a,b都被放到了HashSet中,這樣HashSet就失去了他本身的意義了。


public?class?HashTest?{??

private?int?i;??


public?int?getI()?{??

return?i;??

????}??


public?void?setI(int?i)?{??

this.i?=?i;??

????}??


if?(object?==?null)?{??

return?false;??

????????}??

if?(object?==?this)?{??

return?true;??

????????}??

if?(!(object?instanceof?HashTest))?{??

return?false;??

????????}??

????????HashTest?other?=?(HashTest)?object;??

if?(other.getI()?==?this.getI())?{??

return?true;??

????????}??

return?false;??

????}</strong></span>??


public?int?hashCode()?{??

return?i?%?10;??

????}??


public?final?static?void?main(String[]?args)?{??

HashTest?a?=new?HashTest();??

HashTest?b?=new?HashTest();??

a.setI(1);??

b.setI(1);??

Set?set?=new?HashSet<HashTest>();??

????????set.add(a);??

????????set.add(b);??

????????System.out.println(a.hashCode()?==?b.hashCode());??

????????System.out.println(a.equals(b));??

????????System.out.println(set);??

????}??

}?


返回結果:

true??

true??

[com.ubs.sae.test.HashTest@1]?

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容