覆寫hashCode

sunxiaohang發表於2017-04-05

在比較兩個例項是否相等的時候,通常會覆寫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

相關文章