equals() 預設比較的是什麼?許多初學者以為 equals() 比較「內容」,== 比較「地址」。實則 Object 默認實現:
public boolean equals(Object obj) {
return (this == obj); // 明確是引用地址比較!
}
之所以產生「比較內容」的錯覺,是因為 String、Integer 等封裝類重寫了該方法。例如 String.equals() 逐字符比較值。
hashCode() 的默認行為public native int hashCode(); // 本地方法,典型實現為對象內存地址衍生值
同理,String 重寫為基於字符內容的多項式哈希:
public int hashCode() {
int h = hash;
if (h == 0) {
for (char c : value) h = 31 * h + c;
hash = h;
}
return h;
}
| 規則 | 說明 |
|---|---|
| 一致性 | 若 a.equals(b) == true,則 a.hashCode() == b.hashCode() 必須成立 |
| 非反向性 | hashCode() 相等 不保證 equals() 相等(哈希碰撞) |
| 穩定性 | 對象未修改時,多次調用 hashCode() 應返回同一值 |
在 HashSet、HashMap、Hashtable 等哈希容器中,判斷對象相等流程:
hashCode() —— O(1) 定位桶位equals() —— 精確匹配若無 hashCode() 快速篩選,每次插入/查找都需遍歷全量調用 equals(),性能將退化為 O(n)。
equals() 必須覆寫 hashCode()Objects.equals(a, b)(空安全)、Objects.hash(fields...)(自動合成哈希)@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
User user = (User) o;
return Objects.equals(id, user.id) &&
Objects.equals(name, user.name) &&
Objects.equals(age, user.age);
}
@Override
public int hashCode() {
return Objects.hash(id, name, age);
}
equals() 中用 instanceof 而非 getClass() 會破壞對稱性(子類與父類互相比較)HashMap Key 並在插入後修改字段,會導致數據「丟失」(實則落入錯誤桶位)equals() 與 hashCode() 是 Java 對象身份識別的雙基石。理解其契約、掌握標準重寫模式、避開可變性陷阱,是編寫正確、高性能集合操作代碼的前提。下次重寫時,請讓 IDE 幹髒活,你只負責審核字段選擇是否合理。