首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 程式設計入門

深入解析 equals 契約:JDK 實現缺陷與對稱性破壞實證

     編輯:Java 程式設計入門

equals 契約五大公理

  1. 自反性:o.equals(o) == true
  2. 對稱性:o.equals(o1) → o1.equals(o)
  3. 傳遞性:o.equals(o1) ∧ o.equals(o2) → o1.equals(o2)
  4. 一致性:物件未修改前提下,多次呼叫結果一致
  5. 非空性:o.equals(null) == false

註:以上為 API 規範精簡版,完整定義請參考官方文檔。

Object 預設實現的侷限

Object.equals() 僅比較參考位址(this == obj),即「引用比較」。若需「值比較」,子類別必須覆寫。

JDK 標準實現範本

public boolean equals(Object obj) {
    if (obj == null) return false;
    if (!(obj instanceof FieldPosition)) return false;
    FieldPosition other = (FieldPosition) obj;
    if (attribute == null) {
        if (other.attribute != null) return false;
    } else if (!attribute.equals(other.attribute)) return false;
    return (beginIndex == other.beginIndex
         && endIndex == other.endIndex
         && field == other.field);
}

乍看合理,實則暗藏對稱性破壞風險。

實證:繼承導致 equals 對稱性失效

package debug;
import java.text.*;

public class Test {
    public static void main(String[] args) {
        FieldPosition fp  = new FieldPosition(10);
        FieldPosition fp1 = new MyTest(10);  // 子類別
        System.out.println(fp.equals(fp1));   // true
        System.out.println(fp1.equals(fp));   // false ← 違反對稱性!
    }
}

class MyTest extends FieldPosition {
    int x = 10;
    public MyTest(int x) { super(x); this.x = x; }
    public boolean equals(Object o) {
        if (o == null) return false;
        if (!(o instanceof MyTest)) return false;  // 嚴格檢查自身類別
        // ...
    }
}

根因分析

  • 父類別 FieldPosition.equals 使用 instanceof FieldPosition,子類別實例通過檢查 → 回傳 true
  • 子類別 MyTest.equals 使用 instanceof MyTest,父類別實例失敗 → 回傳 false
  • 導致 fp.equals(fp1) != fp1.equals(fp),嚴重違反契約

最佳實踐建議

  1. 覆寫 equals 時,同時覆寫 hashCode,維持雙向一致性
  2. 使用 getClass() == obj.getClass() 替代 instanceof,確保嚴格類別相等(除非刻意設計跨類別相等)
  3. 考慮使用 Objects.equals() (JDK 7+) 處理 null 安全比較
  4. 不可變類別(如 String、包裝類別)已正確實現,直接使用
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved