Java中的equals和hashCode方法
引言在Java中,、equals()和hashCode()都和對象的比較有關(guān)。但是為什么需要設(shè)計這三種對象的比較方法呢?本文將解釋它們的用途。操作符操作符用于判斷兩個對象是否是同一個對象。對于引用變量
引言
在Java中,、equals()和hashCode()都和對象的比較有關(guān)。但是為什么需要設(shè)計這三種對象的比較方法呢?本文將解釋它們的用途。
操作符
操作符用于判斷兩個對象是否是同一個對象。對于引用變量而言,比較的是兩個引用變量引用的是不是同一個對象,即比較的是兩個引用中存儲的對象地址是不是一樣的。對于基本數(shù)據(jù)類型而言,比較的是兩個數(shù)據(jù)是不是相等。由于基本數(shù)據(jù)類型沒有方法,所以不存在equals()和hashCode()的問題,下面的討論都是針對引用類型而言的。
equals()方法
為什么Java會設(shè)計equals()方法?操作符只能判斷兩個對象是否是同一個對象,這并不能滿足很多需求。有時候當(dāng)兩個對象不是同一個對象的時候,我們?nèi)匀粫J(rèn)為兩者是“相等”的,比如對于String對象,當(dāng)兩個對象的字符串序列是一致的,我們就認(rèn)為他們是“相等”的。對于有這種需求的對象的類,需要重寫其equals()方法來實現(xiàn)具體的“相等”邏輯。需要注意的是,Object類中的默認(rèn)實現(xiàn)是比較兩個對象是不是同一個對象,即其和操作符的效果是相同的。Java提供的某些類已經(jīng)重寫了equals()方法,自己編寫的類如果需要實現(xiàn)自己的“相等”邏輯,也需要重寫equals()方法。
hashCode()方法
為什么會設(shè)計hashCode()方法?hashCode()方法返回的是一個數(shù)值,我們稱之為hashCode。從方法的名稱上就可以看出,其目的是生成一個hash碼。hash碼的主要用途就是在對對象進(jìn)行散列的時候作為key輸入,所以每個對象的hash碼盡可能不同,這樣才能保證散列的存取性能。Object類提供的默認(rèn)實現(xiàn)確保每個對象的hash碼不同(在對象的內(nèi)存地址基礎(chǔ)上經(jīng)過特定算法返回一個hash碼)。根據(jù)Java規(guī)范,hashCode()方法和equals()方法可以沒有關(guān)系。
equals()和hashCode()的關(guān)系
對于集合類HashSet、HashMap等和hash有關(guān)的類,是通過hash算法來散列對象的。對HashSet而言,存入對象的流程為:根據(jù)對象的hash碼,經(jīng)過hash算法,找到對象應(yīng)該存放的位置,如果該位置為空,則將對象存入該位置;如果該位置不為空,則使用equals()比較該位置的對象和將要入的對象,如果兩個相等,則不再插入,如果不相等,則根據(jù)hash沖突解決算法將對象插入其他位置。Java規(guī)定對于HashSet判斷是不是重復(fù)對象就是通過equals()方法來完成,這就需要在兩個對象equals()方法相等的時候,hash碼一定相等(即hashCode()返回的值相等)。假設(shè)兩個對象equals()方法相等的時候,hash碼不相等,會出現(xiàn)equals()相等的兩個對象都插入了HashSet中,這是不允許的。因此我們有以下結(jié)論:對于equals()相等的兩個對象,其hashCode()返回的值一定相等。
如何設(shè)計hashCode()方法
為了保證“對于equals()相等的對象hashCode()要一定相等”,在設(shè)計hashCode()方法時,可以從對象的各個關(guān)鍵域中選取部分或全部字段,通過特定算法得到一個hash碼。同樣地,對于equals()不同的對象,應(yīng)該盡量保證hash碼不同。一個常用的算法如下:
1. 把某個非零常數(shù)值(一般取素數(shù))17保存在int變量result中。
2. 對于對象中的每一個關(guān)鍵域f:
- 如果f是boolean型,計算(f ? 0 : 1)。
- 如果f是byte、char、short型,計算(int)f。
- 如果f是long型,計算(int) (f ^ (f >>> 32))。
- 如果f是float型,計算Float.floatToIntBits(afloat)。
- 如果f是double型,計算(adouble)得到一個long,再執(zhí)行上一步。
- 如果f是對象引用,遞歸調(diào)用它的hashCode()方法。
- 如果f是數(shù)組域,對其中每個元素調(diào)用它的hashCode()方法。
3. 將上面計算得到的散列碼保存到int變量c,然后執(zhí)行result 37 * result c。
4. 返回result。
通過這種算法,可以保證“對于equals()相等的對象hashCode()返回的值一定相等”,并且盡可能使不同的對象產(chǎn)生不同的hash碼。
通過以上分析,我們可以得出equals()和hashCode()在Java中的使用和設(shè)計原則。對于需要進(jìn)行對象比較的類,應(yīng)該重寫equals()方法來實現(xiàn)自定義的“相等”邏輯,并同時重寫hashCode()方法,以滿足equals()和hashCode()的關(guān)聯(lián)要求。這樣可以確保在使用HashSet等集合類時,對象的比較和散列的正確性。