在比較兩個例項是否相等的時候,通常會覆寫equal()方法,然後對類物件的每一成員進行逐一比較,但是JavaSE6規範如下:
應用程式的執行期間,只要物件的equals方法的比較操作所用到的資訊沒有被修改,那麼對這同一個物件呼叫多次,hashCode方法都必須始終如一地返回同一個整數。在同一個應用程式的多次執行過程中,每次執行所返回的整數可以不一致。
如果兩個物件根據equals()方法比較是相等的,那麼呼叫這兩個物件中任意一個物件的hashCode方法都必須產生同樣的整數結果。
如果呼叫父類的equal()
方法,且x.equal(y)
返回值是true,返回的hashCode值卻不同,因此在覆寫equal()方法的同時覆寫hashCode()
方法。這樣才能最大限度地保證,在程式執行過程中儘可能少的出現莫名其妙的錯誤。
再此之前我們先看一下String
類中的hashCode()方法:
public int hashCode() {
int h = hash;
if (h == 0 && value.length > 0) {
char val[] = value;
for (int i = 0; i < value.length; i++) {
h = 31 * h + val[i];
}
hash = h;
}
return h;
}
大家可能會覺得莫名其妙,hashCode()方法返回的是一個int型別的值,難道這就是所謂的hashCode?不要急,我們來看一段話,
一個好的雜湊函式通常傾向於“為不相等的物件產生不相等的雜湊碼”
對於物件中的每個關鍵域f(指equal方法中涉及的每個域),完成以下步驟:
如果該域是boolean型別,則計算
(f?1:0)
;如果該域是byte、char、short或者int計算
(int)f
;如果該域是long型,計算
(int)(f^(f>>>32))
;如果該域是float型別,計算
Float.floatTOIntBits(f)
;如果該域是double型別,計算
Double.doubleToLongBits(f)
,然後再根據long型計算得到雜湊值;如果該域是一個引用物件,並且該類的equal方法通過遞迴呼叫equal的方法來比較這個域,則同樣為這個域遞迴呼叫hashCode,如果這個域為空,則返回0;
-如果該域是一個陣列,則要把每一個元素當作單獨的域來處理按照下面的公式,把上面計算得到的雜湊碼c合併到result中
result=31*result+c
;
————–摘自Effective Java
這是EffectiveJava中給出的計算雜湊碼的方法,當然,方法並不是唯一,只要我們保證相同的物件會產生相同的雜湊碼,不同的獲得的雜湊碼不同就可以了。
現在我們回過頭來看看String
類中的hashCode方法
public int hashCode() {
int h = hash;
if (h == 0 && value.length > 0) {//判斷hash值不為0,字串不為空(即長度大於0)
char val[] = value;//將字串的值轉化為char型陣列
for (int i = 0; i < value.length; i++) {
h = 31 * h + val[i];//遍歷char陣列中的每一個元素通過計算得到hash值
}
hash = h;
}
return h;
}
看到這裡相信大家已經明瞭,hash雜湊碼的意義所在,
這裡我們給出一段三個域都是int
的hash值計算例項
@Override
public int hashCode() {
int result = hashCode;
//生成物件的唯一雜湊碼
if (result == 0) {
result = result * 31 + areaCode;
result = result * 31 + prefix;
result = result * 31 + lineNumber;
hashCode=result;
}
return hashCode;
}
最後,如果大家想深入學習java的話,建議大家看一看effective java,相信會收穫頗豐的。
更多關於java的文章請戳這裡:(您的留言意見是對我最大的支援)
Email:sxh13208803520@gmail.com