马士兵java架构师

您现在的位置是:架构师问答 >

架构师问答

为什么在比较两个对象时,要同时使用 equals() 和 hashCode() 方法?

2023-11-13 15:51:13架构师问答 本文浏览次数:1 百度已收录

本 文 目 录

当我们使用Java中的集合框架(如HashMap、HashSet等)存储或比较对象时,通常会涉及到equals()和hashCode()这两个方法。如果只覆盖其中一个方法而不覆盖另一个,可能会导致意外的行为。下面我们来详细解释原因,并通过代码案例进行说明。

1. 一致性原则

对象在equals()方法中被视为相等,那么在hashCode()方法中也应该返回相同的哈希码。如果不这样做,会导致对象在集合中的行为出现异常

2. 提高性能

在使用HashMap等数据结构时:
hashCode()方法用于快速定位元素可能存在的桶;
而equals()方法用于确认是否真的找到了我们要的元素。
如果hashCode()返回了不同的值,即使equals()返回true,HashMap也会认为这两个对象是不同的。

代码案例:

假设有一个Person类,只覆盖了equals()方法,而没有覆盖hashCode()方法。

public class Person {
    private String name;

    @Override
    public boolean equals(Object obj) {
        if (this == obj) return true;
        if (obj == null || getClass() != obj.getClass()) return false;
        Person person = (Person) obj;
        return Objects.equals(name, person.name);
    }

    // hashCode方法没有被覆盖
}

如果我们尝试将两个equals的Person对象加入到HashSet中:

HashSet<Person> set = new HashSet<>();
Person p1 = new Person();
p1.setName("John");
Person p2 = new Person();
p2.setName("John");
set.add(p1);
set.add(p2);
System.out.println(set.size()); // 输出结果是2而不是1
尽管p1和p2在逻辑上是相等的(因为name都是"John"),但HashSet会认为它们是不同的对象,因为它们的hashCode值不同(默认是对象的内存地址)。
为了避免这种情况,我们需要在重写equals()方法的同时也重写hashCode()方法,确保逻辑相等的对象具有相同的哈希码。

** 所以完整的重写应如下:

@Override
public boolean equals(Object obj) {
    if (this == obj) return true;
    if (obj == null || getClass() != obj.getClass()) return false;
    Person person = (Person) obj;
    return Objects.equals(name, person.name);
}

@Override
public int hashCode() {
    return Objects.hash(name);
}

这样,上述代码中的set.size()就会返回1,因为HashSet正确地认为两个对象是相等的。