這篇文章將為大家詳細(xì)講解有關(guān)為什么要重寫hashCode和equals方法,文章內(nèi)容質(zhì)量較高,因此小編分享給大家做個參考,希望大家閱讀完這篇文章后對相關(guān)知識有一定的了解。
成都創(chuàng)新互聯(lián)公司主要從事網(wǎng)站設(shè)計、網(wǎng)站制作、網(wǎng)頁設(shè)計、企業(yè)做網(wǎng)站、公司建網(wǎng)站等業(yè)務(wù)。立足成都服務(wù)宣州,10多年網(wǎng)站建設(shè)經(jīng)驗,價格優(yōu)惠、服務(wù)專業(yè),歡迎來電咨詢建站服務(wù):028-86922220
如果不被重寫(原生)的hashCode和equals是什么樣的?
不被重寫(原生)的hashCode值是根據(jù)內(nèi)存地址換算出來的一個值。
不被重寫(原生)的equals方法是嚴(yán)格判斷一個對象是否相等的方法(object1 == object2)。
//JAVA代碼: public static void main(String[] args) { Object obj1 = new Object(); Object obj2 = new Object(); Object obj3 = obj2; System.out.println("obj1 equals obj2 ?" + obj1.equals(obj2)); System.out.println("obj2 equals obj3 ?" + obj2.equals(obj3)); System.out.println("obj1's hashcode: " + obj1.hashCode()); System.out.println("obj2's hashcode: " + obj2.hashCode()); System.out.println("obj2's hashcode: " + obj3.hashCode()); } }//輸出結(jié)果:obj1==obj2 ?false obj2==obj3 ?true obj1's hashcode: 12677476 obj2's hashcode: 33263331 obj3's hashcode: 33263331
為什么需要重寫equals和hashCode方法?
如果沒有重寫hashCode和equals方法,比較的是地址值。因為Object的equals方法中使用是==。
在我們的業(yè)務(wù)系統(tǒng)中判斷對象時有時候需要的不是一種嚴(yán)格意義上的相等,而是一種業(yè)務(wù)上的對象相等。在這種情況下,原生的equals方法就不能滿足我們的需求了
所以這個時候我們需要重寫equals方法,來滿足我們的業(yè)務(wù)系統(tǒng)上的需求。那么為什么在重寫equals方法的時候需要重寫hashCode方法呢?
我們先來看一下Object.hashCode的通用約定
在一個應(yīng)用程序執(zhí)行期間,如果一個對象的equals方法做比較所用到的信息沒有被修改的話,那么,對該對象調(diào)用hashCode方法多次,它必須始終如一地返回 同一個整數(shù)。在同一個應(yīng)用程序的多次執(zhí)行過程中,這個整數(shù)可以不同,即這個應(yīng)用程序這次執(zhí)行返回的整數(shù)與下一次執(zhí)行返回的整數(shù)可以不一致。
如果兩個對象根據(jù)equals(Object)方法是相等的,那么調(diào)用這兩個對象中任一個對象的hashCode方法必須產(chǎn)生同樣的整數(shù)結(jié)果。
如果兩個對象根據(jù)equals(Object)方法是不相等的,那么調(diào)用這兩個對象中任一個對象的hashCode方法,不要求必須產(chǎn)生不同的整數(shù)結(jié)果。然而,程序員應(yīng)該意識到這樣的事實,對于不相等的對象產(chǎn)生截然不同的整數(shù)結(jié)果,有可能提高散列表(hash table)的性能。
如果只重寫了equals方法而沒有重寫hashCode方法的話,則會違反約定的第二條:相等的對象必須具有相等的散列碼(hashCode)
同時對于HashSet和HashMap這些基于散列值(hash)實現(xiàn)的類。HashMap的底層處理機(jī)制是以數(shù)組的方法保存放入的數(shù)據(jù)的(Node
如果該數(shù)組位置上已經(jīng)有放入的值了,且傳入的鍵值相等則不處理,若不相等則覆蓋原來的值,如果數(shù)組位置沒有條目,則插入,并加入到相應(yīng)的鏈表中。檢查鍵是否存在也是根據(jù)hashCode值來確定的。所以如果不重寫hashCode的話,可能導(dǎo)致HashSet、HashMap不能正常的運作、
如果我們將某個自定義對象存到HashMap或者HashSet及其類似實現(xiàn)類中的時候,如果該對象的屬性參與了hashCode的計算,那么就不能修改該對象參數(shù)hashCode計算的屬性了。有可能會移除不了元素,導(dǎo)致內(nèi)存泄漏。
擴(kuò)展:
在重寫equals方法的時候,需要遵守下面的通用約定:
1、自反性。
對于任意的引用值x,x.equals(x)一定為true。
2、對稱性。
對于任意的引用值x和y,當(dāng)且僅當(dāng)y.equals(x)返回true時,x.equals(y)也一定返回true。
3、傳遞性。
對于任意的引用值x、y和z,如果x.equals(y)返回true,并且y.equals(z)也返回true,那么x.equals(z)也一定返回true。
4、一致性。
對于任意的引用值x和y,如果用于equals比較的對象沒有被修改的話,那么,對此調(diào)用x.equals(y)要么一致地返回true,要么一致的返回false。
5、對于任意的非空引用值x,x.equals(null)一定返回false。
重寫hashCode方法的大致方式:
a、把某個非零常數(shù)值,比如說17(最好是素數(shù)),保存在一個叫result的int類型的變量中。
b、對于對象中每一個關(guān)鍵域f(值equals方法中考慮的每一個域),完成一些步驟:
1、為該域計算int類型的散列嗎c:
1)、如果該域是boolean類型,則計算(f?0:1)。
2)、如果該域是byte、char、short或者int類型,則計算(int)f。
3)、如果該域是float類型,則計算Float.floatToIntBits(f)。
4)、如果該域是long類型,則計算(int)(f ^ (f>>>32))。
5)、如果該域是double類型,則計算Double.doubleToLongBits(f)得到一個long類型的值,然后按照步驟4,對該long型值計算散列值。
6)、如果該域是一個對象引用,并且該類的equals方法通過遞歸調(diào)用equals的方式來比較這個域,則同樣對這個域遞歸調(diào)用hashCode。如果要求一個更為復(fù)雜的比較,則為這個域計算一個“規(guī)范表示”,然后針對這個范式表示調(diào)用hashCode。如果這個域的值為null,則返回0(或者其他某個常數(shù))
7)、如果該域是一個數(shù)組,則把每一個元素當(dāng)做單獨的域來處理。也就是說,遞歸地應(yīng)用上述規(guī)則,對每個重要的元素計算一個散列碼,然后根據(jù)步驟下面的做法把這些散列值組合起來。
2、按照下面的公式,把步驟1中計算得到的散列碼C組合到result中:
result = 31*result+c。
c、返回result。
d、寫完hashCode方法之后,問自己“是否相等的實例具有相等的散列碼”。如果不是的話,找出原因,并修改。
關(guān)于為什么要重寫hashCode和equals方法就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,可以學(xué)到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。