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

Java equals() 與 == 操作符深度解析:從源碼到實戰的完整對比

     編輯:Java 相關知識

核心結論先行

比較維度== 操作符equals() 方法
本質語言內置運算符Object類實例方法,可覆寫
基本類型比較值不適用(基本類型無方法)
引用類型比較引用地址(是否同一對象)默認比較引用地址,**強烈建議覆寫比較業務值**
null安全null == null 為 truenull.equals(x) 拋NPE,**必須用 Objects.equals(a,b) 或 "const".equals(var)
性能極快(單指令)視實現而定,通常較慢

源碼層面:Object.equals() 默認實現

// java.lang.Object
public boolean equals(Object obj) {
    return (this == obj); // 默認行為:引用比較
}

JDK文檔規定equals必須滿足等價關係:

  • 自反性:x.equals(x) == true
  • 對稱性:x.equals(y) == y.equals(x)
  • 傳遞性:x.equals(y) && y.equals(z) → x.equals(z)
  • 一致性:多次調用結果不變(前提對象未修改)
  • 非空性:x.equals(null) == false
**契約**:覆寫equals**必須**同步覆寫hashCode,否則無法在HashMap、HashSet等集合中正常工作。

經典案例:String.equals() 覆寫實現

// java.lang.String (簡化)
public boolean equals(Object anObject) {
    if (this == anObject) return true; // 引用相同快速返回
    if (anObject instanceof String) {
        String another = (String) anObject;
        if (value.length != another.value.length) return false; // 長度不同快速失敗
        // 逐字符比較值
        for (int i = 0; i < value.length; i++) {
            if (value[i] != another.value[i]) return false;
        }
        return true;
    }
    return false;
}

String.equals() 比較的是字符序列值,而非引用。這是所有值類型(包裝類、集合、業務實體)覆寫equals的標準範式。

實戰對比場景

場景1:字符串字面量 vs new String()

String s1 = "hello";
String s2 = "hello";        // 常量池同一引用
String s3 = new String("hello"); // 堆上新對象

s1 == s2   // true  (同一引用)
s1 == s3   // false (不同引用)
s1.equals(s2) // true (值相同)
s1.equals(s3) // true (值相同)

場景2:包裝類緩存範圍陷阱

Integer a = 127;  // -128~127 緩存
Integer b = 127;
Integer c = 128;  // 超出緩存範圍
Integer d = 128;

a == b   // true  (緩存同一對象)
c == d   // false (新對象)
a.equals(b) // true
c.equals(d) // true
**教訓**:**引用類型絕不使用 == 比較值**,除非確定是同一引用(如枚舉、單例、常量池對象)。

場景3:業務實體比較

@Entity
public class User {
    @Id Long id;
    String username;
    
    @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); // 業務鍵比較
    }
    @Override public int hashCode() { return Objects.hash(id); }
}
  • JPA實體推薦業務鍵(ID)比較,而非全字段比較。
  • 瞬態對象(ID為null)equals通常返回false,避免放入Set時異常。

現代最佳實踐:Java 7+ Objects工具類

// 安全比較,自動處理null
Objects.equals(a, b); // 等價於 a==b || (a!=null && a.equals(b))

// 多字段鏈式比較
Objects.equals(user.getName(), other.getName()) &&
Objects.equals(user.getAge(), other.getAge());

// hashCode自動生成
@Override public int hashCode() { return Objects.hash(id, username); }

IDE生成equals/hashCode模板檢查清單

  1. 是否包含this == o快速判斷?
  2. 是否用getClass() != o.getClass()而非instanceof?(嚴格類型匹配,符合JPA實體規範)
  3. 是否只比較不可變業務鍵字段(ID、唯一業務碼)?
  4. 是否同步生成hashCode且字段集合一致?
  5. 是否處理null安全(用Objects.equals)?

總結

== 是引用身份比較,equals() 是業務值比較(前提是正確覆寫)。**默認規則:基本類型用 ==,引用類型用 Objects.equals()**。理解Object默認實現、String覆寫邏輯、JPA實體業務鍵比較、包裝類緩存陷阱,是寫出正確、高性能Java代碼的基礎功底。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved