目录

Java hashCode 和 equals

揭秘 equals 和 hashCode

1. equals 的作用

在 Object 类的源码中,equals 方法如下定义:

1
2
3
public boolean equals(Object obj) {
    return (this == obj);
}

简而言之,equals 方法的作用是判断两个对象是否相等。

对于没有被覆写的 Java 类,通过 equals() 进行两个对象的比较等价于 ==。对于 equals()== 的区别,在 Java String及其相关类 中的字符串比较部分已举例说明。

2. 何时需要覆写 hashCode() 和 equals()?

上文提到,没有被覆写的 equals() 相当于 ==,所以要实现比较两个对象的内容是否相等,就需要覆写 equals()

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
public class Person {
    private String name;
    private int age;
    
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    
    // p1 = p2 = new Person("MicroLOONG", 21)
    public boolean isEquals(Person p1, Person p2) {
        return p1.equals(p2);
    }
}

以上例子的 isEquals 方法返回 false,因为 p1p2 内容虽然相同但不是相同的对象。

通过 IDE 的 生成 equals() 和 hashCode() 功能可以直接生成相应代码,后期可以根据相关业务需求进行修改。通过重写 equals() 同类型同内容不同引用的情况也能正确的返回 true

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
@Override
public boolean equals(Object obj) {
    // 如果引用指向同一个对象,返回 true
    if (this == obj) {
        return true;
    }
    // 如果为 null,或者并非同类,返回 false
    if (obj == null || getClass() != obj.getClass()) {
        return false;
    }
    // 强制转换
    Person person = (Person) obj;
    // 判断两个属性值是否相等
    return age == person.age && Objects.equals(name, person.name);
}

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

3. 为什么覆写 equals() 时必须覆写 hashCode()?

hashCode 方法将返回 int 类型的哈希值,该值确定对象在哈希表中的索引位置。由于不可避免的会存在哈希值冲突情况(两个不同的键值对,哈希值相等),当 hashCode 相同时,还需要调用 equals() 进行比较;若 hashCode 不同,将直接判定为对象不同,而跳过执行 equals(),加快了处理效率。

假设上文例子 Person 类只覆写了 equals() 没有覆写 hashCode(),现有两个 Person 对象 p1p2

1
2
3
4
5
6
7
8
Person p1 = new Person("MicroLOONG", 21);
Person p2 = new Person("MicroLOONG", 21);

Set<Person> hashSet = new HashSet<>();
hashSet.add(p1);
hashSet.add(p2);
// 输出大小
System.out.println(hashSet.size());

将这两个对象放到 Set 集合,输出结果是 2。根据 Set 存储的是不重复的对象,结果应该为1。但是因为没有覆写 hashCode(),即使 equals() 相等,hashCode() 得到的是一个与对象地址相关的唯一数值,hashCode() 不同,所以两个本应相等的对象被判定为不相等。如果想存储不重复的元素,那么就需要覆写 hashCode()

hashCode 和 HashMap

equals并非万能(BigDecimal)

总结

  • 如果两个对象的 equals() 结果是相等的,则两个对象的 hashCode() 返回结果也必须是相同的;如果两个对象有相同的 hashCode 值,它们不一定是相等的(哈希冲突)。
  • 任何时候覆写 equals(),都必须同时覆写 hashCode(),否则两个对象无论如何都不会相等。