为什么重写 equals 还要重写 hashCode,不重写会有什么问题?

112 阅读2分钟

1. 首先我们要理清楚为什么我们要重写equals

查看Object类种equals方法源码,被重写了这么多次,看来重写是很有必要的😼

image.png 很显然,equals的本质就是==,如果你不重写的话

  • 让我们复习下 ==

基本类型:比较的是值是否相同;
引用类型:比较的是引用是否相同

  • 所以为了达到值比较的效果,JDK已经是帮我们把String和Integer重写了hh

2. 那么现在我们来重写一次equals方法

场景: 假设一个User对象有以下属性

public class User {
    private String username;
    private String  id;
    private int age;
    }
  • 如果我们不重写equals方法,那么就算你new出的user实例各项值一样,equal的结果永远是false,正如上文说的,equals在对于引用类型的时候比较的是引用是否相同,也就是在内存中位置是否相同,hashcode同理

v2-27b993f8ee6ae4771ee9777c625561a0_1440w.png

New一个新的对象便会开辟一个新的内存空间,那么如何重写呢?🤨

代码如下:

@Override
public boolean equals(Object obj) {
    if (obj instanceof User) {
        User user = (User) obj;
        //这里注意age的数据类型是基础数据类型,所以用==比较
        if (user.getAge() == this.age && user.getId().equals(this.id) && user.getUsername().equals(this.username)) {
            return true;
        }else {
            return false;
        }
    }else {
        return false;
    }
}

测试结果为True

User user1 = new User("zyx", "1001", 18);
User user2 = new User("zyx", "1001", 18);
System.out.println("equals result: " + user1.equals(user2));

image.png

3. 为什么说重写equals方法后需要重写hashCode呢

  • 先让我们来看看不重写hashcode会导致什么吧 代码如下:
User user1 = new User("zyx", "1001", 18);
User user2 = new User("zyx", "1001", 18);
HashMap map = new HashMap<>();
HashSet set = new HashSet<>();
System.out.println("equals result: " + user1.equals(user2));
System.out.println("user1 hashcode" + user1.hashCode());
System.out.println("user2 hashcode" + user2.hashCode());
map.put(user1, user2);
map.put(user2, user1);
set.add(user1);
set.add(user2);
//基于HashMap和HashSet的特性,我们期待的结果应该是长度均为1
System.out.println("map length:" + map.size());
System.out.println("set length:" + set.size());

打印测试结果:

image.png

  • 很显然结果不如我们所料
  • 这是因为HashMap、HashSet中是先判断两者hashcode是否相同,(即HashMap存储时候根据Key的hashcode决定存储位置),再使用equals作比较

代码如下:

@Override
public int hashCode() {
    //这里可以调用String重写过的hashCode
    int result = this.username.hashCode();
    result += this.id.hashCode();
    result += age;
    return  result;
}

打印结果:

image.png

这就是为什么重equals后还要重写hashCode😁

4. HashMap、HashSet的扩展知识

  • 小记下,下次补😴