關(guān)于Object中equals方法和hashCode方法判斷的分析
首先提出這樣一個(gè)問題:
如果兩個(gè)對象不相同,他們的hashCode值一定不相等嗎?
我們都知道equals和hashCode是Object中的方法,java中每一個(gè)對象都具有這兩個(gè)方法。
- equals(Object obj):判斷兩個(gè)對象是否“相同”,返回true或false;
public boolean equals(Object obj) { return (this == obj); }
- hashCode():將該對象的內(nèi)部地址作為一個(gè)int值返回
public native int hashCode();
再來看兩條關(guān)于這兩個(gè)方法的規(guī)范:
- 如果重寫equals(Object obj)方法,有必要重寫hashCode()方法,以確保equals(Object obj)方法返回為true的兩個(gè)對象有相等的hashCode()返回值。也就是說,如果兩個(gè)對象相同,他們的hashCode值應(yīng)該相等;
- 如果equals(Object obj)方法返回false,即兩個(gè)對象不“相同”,并不要求這兩個(gè)對象調(diào)用hashCode()方法有不相等的返回值。也就是說,如果兩個(gè)對象不相同,他們的hashCode可能相等。
當(dāng)然,上述只是規(guī)范。針對規(guī)范1,如果重寫equals(Object obj)返回true,而hashCode()方法返回不相等的值,也是可以編譯過的。
這樣我們可以作出如下推論:
- 如果兩個(gè)對象equals,理論上講他們的hashCode一定相等(至少Java環(huán)境會(huì)這樣認(rèn)為);
- 如果兩個(gè)對象不equals,他們的hashCode有可能相等;
- 如果兩個(gè)對象hashCode相等,他們不一定equals;
- 如果兩個(gè)對象hashCode不相等,他們一定不equals。
看著有點(diǎn)繞,其實(shí)原理很簡單。我們從推論3和推論4可以預(yù)測:
Java在判斷兩個(gè)對象是否“相同”時(shí),首先判斷他們的hashCode()方法是否返回相等的int值,其次判斷equals方法是否返回true。
我們可以寫一段簡單的代碼測試一下:
首先寫一個(gè)Java類:
public class Person { //重寫equals方法,始終返回false; @Override public boolean equals(Object obj) { System.out.println("判斷Person的equals"); return false; } //重寫hashCode方法,始終返回1; @Override public int hashCode() { System.out.println("判斷Person的hashCode"); return 1; } }
上述代碼中Person類重寫了equals方法,打印并始終返回false,重寫了hashCode方法,打印并始終返回1。
我們都知道Map中要求鍵不能重復(fù),也就是不能“相同”,所以可以寫如下的測試類:
public class TestPerson { @Test public void test(){ Map<Person,Object> map = new HashMap<>(); map.put(new Person(),new Object());//放入第1個(gè)Person-Object鍵值對; System.out.println("====================="); map.put(new Person(),new Object());//放入第2個(gè)Person-Object鍵值對; System.out.println(map.size()); } }
運(yùn)行,打印結(jié)果如下
判斷Person的hashCode
=====================
判斷Person的hashCode
判斷Person的equals
2
我們來分析一下:
- 當(dāng)放入第1個(gè)Person-Object鍵值對時(shí),Java會(huì)判斷map中有沒有和當(dāng)前添加的new Person()相同的對象,于是去調(diào)用了Person的hashCode()方法,得到返回值1,發(fā)現(xiàn)此時(shí)map中沒有相等的hashCode為1的Person對象(因?yàn)榇藭r(shí)map為空),所以不再判斷equals方法,將這個(gè)鍵值對放入map中;(推論4:如果兩個(gè)對象hashCode不相等,他們一定不equals)
- 當(dāng)放入第2個(gè)Person-Object鍵值對時(shí),Java依然采用相同的判斷方式,hashCode()方法判斷之后得到返回值為1,發(fā)現(xiàn)此時(shí)map中有相等的hashCode值的Person對象,然后再去判斷equals方法,得到返回值false(推論3:如果兩個(gè)對象的hashCode相等,他們不一定equals),認(rèn)為這兩個(gè)對象不相同,于是將第2個(gè)鍵值對也放入map中。執(zhí)行之后得到map的size為2
所以可以得出結(jié)論:
Java在判斷兩個(gè)對象是否“相同”時(shí),首先判斷他們的hashCode()方法是否返回相等的int值,如果不相等則直接認(rèn)為他們不“相同”,如果相等,再判斷equals方法是否返回true。
針對上述代碼,可以在equals方法和hashCode方法中分別打斷點(diǎn),Debug運(yùn)行,這樣會(huì)看得比較清楚一點(diǎn)。
我們回到最初的那個(gè)問題:如果兩個(gè)對象不相同,他們的hashCode值一定不相等嗎?
上述代碼中的場景就充分說明兩個(gè)對象不相同時(shí)hashCode值卻相等的場景,當(dāng)然,這是不按照規(guī)范操作的情況。所以寫代碼時(shí)一定要按照規(guī)范要求的去做,避免不必要的BUG
可以試想一下,如果將上述代碼中重寫equals方法中的始終返回false改為始終返回true,又會(huì)是怎樣的結(jié)果。
總結(jié)
以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,謝謝大家對腳本之家的支持。如果你想了解更多相關(guān)內(nèi)容請查看下面相關(guān)鏈接
相關(guān)文章
分布式系統(tǒng)下調(diào)用鏈追蹤技術(shù)面試題
這篇文章主要為大家介紹了分布式系統(tǒng)下調(diào)用鏈追蹤技術(shù)面試問題合集,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪2022-03-03java在linux本地執(zhí)行shell命令的實(shí)現(xiàn)方法
本文主要介紹了java在linux本地執(zhí)行shell命令的實(shí)現(xiàn)方法,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-02-02Java數(shù)據(jù)導(dǎo)出功能之導(dǎo)出Excel文件實(shí)例
這篇文章主要介紹了Java數(shù)據(jù)導(dǎo)出功能之導(dǎo)出Excel文件實(shí)例,本文給出了jar包的下載地址,并給出了導(dǎo)出Excel文件代碼實(shí)例,需要的朋友可以參考下2015-06-06HashMap工作原理_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
這篇文章主要介紹了HashMap工作原理_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理,需要的朋友可以參考下2017-04-04Java NIO Path接口和Files類配合操作文件的實(shí)例
下面小編就為大家分享一篇Java NIO Path接口和Files類配合操作文件的實(shí)例,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2017-11-11Spring?Boot實(shí)現(xiàn)MyBatis動(dòng)態(tài)創(chuàng)建表的操作語句
這篇文章主要介紹了Spring?Boot實(shí)現(xiàn)MyBatis動(dòng)態(tài)創(chuàng)建表,MyBatis提供了動(dòng)態(tài)SQL,我們可以通過動(dòng)態(tài)SQL,傳入表名等信息然組裝成建表和操作語句,本文通過案例講解展示我們的設(shè)計(jì)思路,需要的朋友可以參考下2024-01-01