| 比較維度 | == 操作符 | equals() 方法 |
|---|---|---|
| 本質 | 語言內置運算符 | Object類實例方法,可覆寫 |
| 基本類型 | 比較值 | 不適用(基本類型無方法) |
| 引用類型 | 比較引用地址(是否同一對象) | 默認比較引用地址,**強烈建議覆寫比較業務值** |
| null安全 | null == null 為 true | null.equals(x) 拋NPE,**必須用 Objects.equals(a,b) 或 "const".equals(var) |
| 性能 | 極快(單指令) | 視實現而定,通常較慢 |
// java.lang.Object
public boolean equals(Object obj) {
return (this == obj); // 默認行為:引用比較
}
JDK文檔規定equals必須滿足等價關係:
x.equals(x) == truex.equals(y) == y.equals(x)x.equals(y) && y.equals(z) → x.equals(z)x.equals(null) == false**契約**:覆寫equals**必須**同步覆寫hashCode,否則無法在HashMap、HashSet等集合中正常工作。
// 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的標準範式。
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 (值相同)
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
**教訓**:**引用類型絕不使用 == 比較值**,除非確定是同一引用(如枚舉、單例、常量池對象)。
@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); }
}
equals通常返回false,避免放入Set時異常。// 安全比較,自動處理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); }
this == o快速判斷?getClass() != o.getClass()而非instanceof?(嚴格類型匹配,符合JPA實體規範)hashCode且字段集合一致?null安全(用Objects.equals)?== 是引用身份比較,equals() 是業務值比較(前提是正確覆寫)。**默認規則:基本類型用 ==,引用類型用 Objects.equals()**。理解Object默認實現、String覆寫邏輯、JPA實體業務鍵比較、包裝類緩存陷阱,是寫出正確、高性能Java代碼的基礎功底。