编程Java开发者

解释Java中equals()方法的特点:何时以及为什么要重写,如何正确实现,以及在错误使用时可能出现的问题。

用 Hintsage AI 助手通过面试

回答

equals()方法用于确定两个对象是否被认为是“相等的”。默认情况下,它比较引用(即==),但通常类(例如实体、值对象)需要基于数据的逻辑比较。

何时重写:

  • 如果你的类对对象的逻辑身份很重要(例如,两个具有相同电子邮件的用户是“同一个用户”)
  • 如果对象将存储在使用equals(和hashCode)的集合中(例如,HashSet)

要求:

  • equals必须是自反的,对称的,传递的,一致的,并且对于任何非空x,x.equals(null)必须为false
  • 在重写equals时,必须重写hashCode!

示例:

public class Person { private String email; @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Person person = (Person) o; return Objects.equals(email, person.email); } @Override public int hashCode() { return Objects.hash(email); } }

诱导性问题

如果两个对象在equals()中相等,它们的hashCode()是否总是相同的?

回答: 是的!这是Java合同的要求。但是反之则不然:两个具有相同hashCode的对象可能在equals()中不相等——哈希码可能会因不同对象而相同(冲突)。

错误示例:

person1.equals(person2); // true person1.hashCode() != person2.hashCode(); // 错误!

由于对主题细微之处不够了解而导致的实际错误示例


故事

在企业应用中,User实体被放入HashSet。重写了equals,但没有重写hashCode。在修改影响equals的字段后,HashSet“丢失”了这个对象:使用contains方法的搜索返回false,即使数据相同。


故事

在IoT项目中,实体最初仅按id进行比较,之后逻辑更改为考虑名称的equals。HashMap开始表现得不可预测,在更新键时出现重复项——由于实现版本的混合违反了equals/hashCode的合同。


故事

在编写比较订单的API时,两个不同的类实现了自己的equals,一个调用getClass(),另一个使用instanceof。这导致了不对称的订单比较,并在使用集合和业务逻辑时出现了错误。