在覆寫 equals 時要一併覆寫 hashCode,如果沒有覆寫 hashCode,會造成利用 hashCode 作判斷的方法失常。
在覆寫 hashCode 時要注意幾點規定:
- 在不改變 equals 方法及 field 內容的前提下,每次調用同一實體的 hashCode,結果須一致。
- 若兩物件用 equals 比對為 true,則它們的 hashCode 必相同。a.equals(b) 為 true,那麼 a.hashCode = b.hashCode。
- 若兩物件用 equals 比對為 false,則它們的 hashCode 不一定要不同,就是說 hashCode 仍有機會是一樣的。a.equals(b) 為 false,a.hashCode = b.hashCode 或 a.hashCode != b.hashCode 都可以。
public class Seat {
private final String room;
private final String table;
public Seat(String room, String table) {
this.room = room;
this.table = table;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Seat seat = (Seat) o;
return room.equals(seat.room) && table.equals(seat.table);
}
}
覆寫 equals 後,如果兩個 Seat 邏輯一樣,但沒有覆寫 hashCode,無法辨識出兩個 Seat 是一樣的,因為在 HashMap 會先用 hashCode 來判斷,當 hashCode 一樣後,才會調用 equals 來比對。Map<Seat, String> map = new HashMap<>();
map.put(new Seat("301", "A01"), "Dana");
map.put(new Seat("301", "A01"), "Dana");
System.out.println(map.size()); // 2
如果覆寫 hashCode 後,所有 Seat 都回傳一樣的 hash code,那麼會發生什麼事? 這樣的寫法是符合上面 3 項規定的,那會有問題嗎? 有,這樣就失去 hash 的意義,hash 是希望分配,減少碰撞。如果 hashCode 全部一樣,就像是丟到同一 bucket,基本上跟沒有 hash 一樣!Java基礎:講講 HashCode 的作用覆寫 hashCode 時要注意以下幾點:
https://www.gushiciku.cn/pl/gkK1/zh-tw
- 給一個常數 c,多為質數。
- 對 equals 方法中使用的每一 field,計算 hashCode。基本型態,用該型態自有的 hashCode 方法,像是 Short.hashCode(s),若為物件,則需要遞迴地找出該物件的 hashCode。
- 將每一個 hashCode 作乘法運算並與 c 相加,返回結果。
@Override
public int hashCode() {
return Objects.hash(room, desk);
}
當一個 class 為不可變時,表示它的 hashCode 調用較頻繁,重複計算是耗時的,所以可以考慮將 hashCode 計算後儲存起來。另外,不要對 hashCode 的實作作保證,如果開發者或客戶依賴這樣的假設,未來要更改實作就會比較難。// java.lang.String source code
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
/** The value is used for character storage. */
private final char value[];
/** Cache the hash code for the string */
private int hash; // Default to 0
...
}
轉載請註明原文網址 https://cookieandcoketw.blogspot.com/2020/07/effective-java-11-override-equals-and-hashcode.html
沒有留言:
張貼留言