Skip to content

equals() 方法

equals 是什么?

equals() 用来判断两个对象是否「相等」。Object 类的默认实现用 == 比较地址,所以不重写的话,两个对象永远不可能相等(除非是同一个引用)。

实际开发中,我们经常需要判断「内容相等」——比如两个订单号相同的订单被认为是同一个订单。

默认实现

java
public class Object {
    public boolean equals(Object obj) {
        return (this == obj); // 只是比较地址
    }
}

重写 equals

基本重写模式

java
class Person {
    private String name;
    private int age;

    @Override
    public boolean equals(Object o) {
        // 1. 自反性:自己和自己比
        if (this == o) return true;

        // 2. 非空检查
        if (o == null) return false;

        // 3. 类型检查(或者用 instanceof)
        if (getClass() != o.getClass()) return false;

        // 4. 比较属性
        Person other = (Person) o;
        return age == other.age && Objects.equals(name, other.name);
    }
}

equals 契约(五条规则)

规则含义示例
自反性x.equals(x) 必须 true自己和自己相等
对称性x.equals(y)y.equals(x) 结果相同A==B 则 B==A
传递性A==B 且 B==C,则 A==C相等关系可传递
一致性多次调用结果不变状态不变则相等性不变
非空性x.equals(null) 必须 false任何对象都不等于 null

用 instanceof 还是 getClass()?

java
// 方式一:getClass() — 严格相等,子类不兼容
class Person {
    @Override
    public boolean equals(Object o) {
        if (getClass() != o.getClass()) return false;
        // ...
    }
}

class Employee extends Person { } // Employee.equals(Person) 永远 false
java
// 方式二:instanceof — 宽松相等,子类也兼容
class Person {
    @Override
    public boolean equals(Object o) {
        if (!(o instanceof Person p)) return false;
        // ...
    }
}

class Employee extends Person { } // Employee 可以和 Person 比较

通常用 getClass() 更安全,避免子类破坏对称性。

常见错误

错误一:只比较部分属性

java
class Point {
    private int x, y, z;

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        Point p = (Point) o;
        return x == p.x && y == p.y;
        // ❌ 忘记比较 z!三个点的对象会不相等
    }
}

错误二:不处理 null 属性

java
@Override
public boolean equals(Object o) {
    // ❌ 直接调用 name.equals(),如果 name 是 null 会 NPE
    return name.equals(((Person) o).name);
}

// ✅ 正确做法:使用 Objects.equals()
return Objects.equals(name, other.name); // 内部已做 null 检查

错误三:equals 和 hashCode 不一致

java
class Broken {
    private String name;

    @Override
    public boolean equals(Object o) {
        return o instanceof Broken b && name.equals(b.name);
    }

    @Override
    public int hashCode() {
        return name.hashCode() + new Random().nextInt(100);
        // ❌ hashCode 可能不同,违反约定!
    }
}

// 使用时出问题
Broken a = new Broken("test");
Broken b = new Broken("test");
Set<Broken> set = new HashSet<>();
set.add(a);
System.out.println(set.contains(b)); // 可能是 false!HashMap 的噩梦

IDE 自动生成

实际开发中,用 IDE 生成 equals 和 hashCode 是标准做法:

java
// IntelliJ: Alt+Insert → equals() and hashCode()

@Data
class Person {
    private String name;
    private int age;
}

IDE 生成的方法通常比手写的更完善。

equals vs ==

java
String a = new String("hello");
String b = new String("hello");

a == b;       // false,地址不同
a.equals(b);  // true,内容相同

String c = "hello";
String d = "hello";

c == d;       // true,字符串常量池复用
c.equals(d);  // true,内容相同

记住:== 比较地址,equals 比较内容(重写后)。

总结

重写 equals 的检查清单:

  1. ✅ 用 this == o 检查自反性
  2. ✅ 检查 null
  3. ✅ 用 getClass()instanceof 检查类型
  4. ✅ 比较所有「有意义」的属性
  5. ✅ 使用 Objects.equals() 处理可能的 null
  6. 同时重写 hashCode,保持一致

基于 VitePress 构建