为什么重写equals方法就要同时重写hashcode

hashCode重写规则

  • 两个对象相同,hashCode一定相等
  • 两个对象不等,hashCode可以相等也可以不相等
  • hashCode相等的两个对象不一定相等
  • hashCode不等的两个对象一定不相等

为什么重写equals方法就要同时重写hashcode

在Java中,equals方法用于比较两个对象是否相等,而hashCode方法用于返回对象的哈希码。根据Java的规范,如果两个对象通过equals方法被认为是相等的,那么它们的hashCode方法必须返回相同的值。这是因为在使用哈希表(如HashMapHashSet等)时,哈希码用于快速定位对象的位置。如果两个相等的对象有不同的哈希码,那么在哈希表中可能会导致查找失败或数据不一致。

简单说,就是map集合里面,因为要用到hashCode方法计算key,所以自定义对象就算里面的值相同,也会计算出不同的hashCode值,从而让相同的数据存储到不同的桶中。 这样的话,就会导致set集合里面的元素无法去重,map集合里面的key无法覆盖。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
package org.example;

import java.util.*;

//TIP To <b>Run</b> code, press <shortcut actionId="Run"/> or
// click the <icon src="AllIcons.Actions.Execute"/> icon in the gutter.
public class Main {
    public static void main(String[] args) {
        Person liming = new Person("liming");
        Person zhangsan = new Person("liming");
        System.out.println(liming.hashCode());
        System.out.println(zhangsan.hashCode());
        System.out.println(liming.equals(zhangsan));

        Set<Person> set = new HashSet<>();
        set.add(liming);
        set.add(zhangsan);
        System.out.println(set.toString());
        HashMap<Object, String> map = new HashMap<Object, String>();
        Person p1 = new Person("Alice");
        Person p2 = new Person("Alice");
        map.put(p1, "Engineer");
        map.put(p2, "Teacher");
        System.out.println(map.get(p1));
        System.out.println(map.get(p2));
    }
}

class Person {
    private String name;

    Person(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

  

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                '}';
    }


}

看这个例子

https://blog.meowrain.cn/api/i/2025/07/04/xlygs0-1.webp

因为默认用的Object类的hashCode方法,所以两个对象的哈希码是不同的,导致它们在集合中被认为是不同的对象。 equals方法默认比较的是对象的引用地址,所以两个对象虽然内容相同,但被认为是不同的对象。

可以看到,set没能完成去重,map也没能覆盖。

https://blog.meowrain.cn/api/i/2025/07/04/xk7aog-1.webp

那只重写equals方法会怎么样呢?

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
package org.example;

import java.util.*;

//TIP To <b>Run</b> code, press <shortcut actionId="Run"/> or
// click the <icon src="AllIcons.Actions.Execute"/> icon in the gutter.
public class Main {
    public static void main(String[] args) {
        Person liming = new Person("liming");
        Person zhangsan = new Person("liming");
        System.out.println(liming.hashCode());
        System.out.println(zhangsan.hashCode());
        System.out.println(liming.equals(zhangsan));

        Set<Person> set = new HashSet<>();
        set.add(liming);
        set.add(zhangsan);
        System.out.println(set.toString());
        HashMap<Object, String> map = new HashMap<Object, String>();
        Person p1 = new Person("Alice");
        Person p2 = new Person("Alice");
        map.put(p1, "Engineer");
        map.put(p2, "Teacher");
        System.out.println(map.get(p1));
        System.out.println(map.get(p2));
    }
}

class Person {
    private String name;

    Person(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = 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 name.equals(person.getName());
    }



    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                '}';
    }


}

https://blog.meowrain.cn/api/i/2025/07/04/xn4xq1-1.webp

可以看到hashCode不同,但equals相同,但是因为set底层是基于map实现的,所以set集合里面的元素还是没能去重。

只重写hashCode方法会怎么样呢?

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
package org.example;

import java.util.*;

//TIP To <b>Run</b> code, press <shortcut actionId="Run"/> or
// click the <icon src="AllIcons.Actions.Execute"/> icon in the gutter.
public class Main {
    public static void main(String[] args) {
        Person liming = new Person("liming");
        Person zhangsan = new Person("liming");
        System.out.println(liming.hashCode());
        System.out.println(zhangsan.hashCode());
        System.out.println(liming.equals(zhangsan));

        Set<Person> set = new HashSet<>();
        set.add(liming);
        set.add(zhangsan);
        System.out.println(set.toString());
        HashMap<Object, String> map = new HashMap<Object, String>();
        Person p1 = new Person("Alice");
        Person p2 = new Person("Alice");
        map.put(p1, "Engineer");
        map.put(p2, "Teacher");
        System.out.println(map.get(p1));
        System.out.println(map.get(p2));
    }
}

class Person {
    private String name;

    Person(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }


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

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                '}';
    }


}

https://blog.meowrain.cn/api/i/2025/07/04/xnwr77-1.webp

我们来看看判重逻辑:

https://blog.meowrain.cn/api/i/2025/07/04/xosnm4-1.webp

可以看到,hashCode相同,但equals不同,所以set集合里面的元素还是没能去重。

全部重写

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
package org.example;

import java.util.*;

//TIP To <b>Run</b> code, press <shortcut actionId="Run"/> or
// click the <icon src="AllIcons.Actions.Execute"/> icon in the gutter.
public class Main {
    public static void main(String[] args) {
        Person liming = new Person("liming");
        Person zhangsan = new Person("liming");
        System.out.println(liming.hashCode());
        System.out.println(zhangsan.hashCode());
        System.out.println(liming.equals(zhangsan));

        Set<Person> set = new HashSet<>();
        set.add(liming);
        set.add(zhangsan);
        System.out.println(set.toString());
        HashMap<Object, String> map = new HashMap<Object, String>();
        Person p1 = new Person("Alice");
        Person p2 = new Person("Alice");
        map.put(p1, "Engineer");
        map.put(p2, "Teacher");
        System.out.println(map.get(p1));
        System.out.println(map.get(p2));
    }
}

class Person {
    private String name;

    Person(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = 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 name.equals(person.getName());
    }

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

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                '}';
    }


}

https://blog.meowrain.cn/api/i/2025/07/04/xp40ty-1.webp


相关内容

0%