1. 程式人生 > >基礎 | 重寫hashCode方法

基礎 | 重寫hashCode方法

參加美團秋招面試時,被問到 「如何重寫hashCode方法?重寫hashCode()方法需要注意什麼?」,在此做一個系統的總結與梳理,同時也填一下之前埋下的坑,哈哈。


參考答案

為什麼要重寫hashCode()方法?

Object類中hashCode()方法預設是將物件的儲存地址進行對映,並返回一個整形值作為雜湊碼。

若重寫equals()方法,使其比較兩個物件的內容,並保留hashCode()方法的預設實現,那麼兩個明明「相等」的物件,雜湊值卻可能不同。

如果兩個物件通過equals()方法比較的結果為true,那麼要保證這兩個物件的雜湊值相等。

因此,在重寫equals()方法時,建議一定要重寫hashCode()方法。

如何重寫hashCode()方法?

由於Object類的 hashCode() 方法是本地的(native),故其具體實現並不是由Java所完成的。

需要實現hashCode()方法時,可以直接呼叫Objects.hash(Object… values)方法來獲取對應的雜湊值。其內部的具體實現是呼叫Arrays.hashCode(Object[])方法來完成的。

Arrays中計算雜湊值的核心程式碼如下:

public static int hashCode(Object a[]) {
if (a == null) return 0; int result = 1; for (Object element : a) result = 31 * result + (element == null ? 0 : element.hashCode()); return result; }

那麼,為什麼選擇數字31作為計算雜湊值的因數

The value 31 was chosen because it is an odd prime. If it were even and the multiplication overflowed, information would be lost, as multiplication by 2 is equivalent to shifting. The advantage of using a prime is less clear, but it is traditional. A nice property of 31 is that the multiplication can be replaced by a shift and a subtraction for better performance: 31 * i == (i << 5) - i

. Modern VMs do this sort of optimization automatically. ------引用自《Effective Java》

重寫hashCode()方法需要注意什麼?

  • 應用程式執行期間,只要一個物件用於equals()方法的屬性未被修改,則該物件多次返回的雜湊值應相等。
  • 如果兩個物件通過equals()方法比較的結果為true,那麼要保證這兩個物件的雜湊值相等。
  • 如果兩個物件通過equals()方法比較的結果為false,那麼這兩個物件的雜湊值可以相等也可以不相等,但理想情況下是應該不相等,以提高散列表的效能。

原始碼閱讀

// Object類中hashCode()方法的預設實現
public native int hashCode();
// Arrays中計算雜湊值的核心程式碼
public static int hashCode(Object a[]) {
    if (a == null)
        return 0;

    int result = 1;

    for (Object element : a)
        result = 31 * result + (element == null ? 0 : element.hashCode());

    return result;
}

推薦閱讀


歡迎關注

Java名企面試吧,每天10點24分,我們不見不散!

丙子先生的宗旨是,每天以短篇幅講高頻面試題,不增加太多負擔,但需要持之以恆。

能力有限,歡迎指教!