覆盖equals时请遵守通用约定

何时需要覆盖 equals 方法?

在 Java 中,默认的 equals 方法(继承自 Object 类)比较的是对象的内存地址(即 == 的行为)。但在以下场景中,需要覆盖 equals 以实现基于对象内容的逻辑相等性判断:

  1. 需要基于字段值判断对象相等性
    场景:当两个对象的关键字段(如 ID、名称等)值相同时,应视为逻辑上的“相等”,即使它们是不同的对象实例。
  2. 对象将作为集合元素使用
    场景:当对象被添加到 Set、用作 Map 的键,或需要调用 List.contains() 时,必须正确实现 equals 和 hashCode,否则集合无法正确识别相等对象。

举个例子 🌰

Set<Person> personSet = new HashSet<>();
Person p1 = new Person("007", "Abc");
Person p2 = new Person("007", "Abc");

personSet.add(p1);
System.out.println(personSet.contains(p2)); // 若未覆盖 equals,返回 false;覆盖后返回 true
  1. 需要自定义相等性规则
    场景:当业务逻辑需要比较对象内容而非内存地址时

不需要覆盖 equals 的情况

  1. 类的每个实例本质上是唯一的
    如 Thread、Enum 类型,Object 的默认实现已足够
  2. 父类已提供合适的equals实现
    如大多数 List 实现继承自 AbstractList

覆盖 equals 方法遵守五大通用约定

  1. 自反性:任何非null对象必须等于自身
    x.equals(x) 必须返回 true
  2. 对称性:比较结果不应依赖于比较顺序
    如果 x.equals(y) 返回 true,则 y.equals(x) 也必须返回 true
  3. 传递性:相等关系应能传递
    如果 x.equals(y) 和 y.equals(z) 都返回 true,则 x.equals(z) 也必须返回 true
  4. 一致性:多次比较结果应稳定
    只要对象未被修改,多次调用 equals() 应返回相同结果
  5. 非空性:任何对象不应等于null
    x.equals(null) 必须返回 false

覆盖 equals 的强制要求

覆盖了 equals(),必须同时覆盖 hashCode()
若 x.equals(y) 返回 true,则 x.hashCode() 必须等于 y.hashCode()。
违反此规则会导致对象在哈希集合(如 HashSet, HashMap)中行为异常。

始终要覆盖toStrng

重写 toString() 方法的目的是为对象提供清晰、可读的字符串表示。

场景

  1. 在字符串拼接:String s = "Person: " + person;
  2. 日志输出:log.info("User: {}", person);
  3. 直接输出对象信息:System.out.println(person);

以上会隐式调用toString() 方法

参考《Effective Java》

我爱吃炒煤
1 声望0 粉丝