通俗易懂的理解为什么重写了equals,必须重写hashcode

在实际项目中或者面试中我们经常能遇到,重写equals,就必须重写hashcode,很多小伙伴不知道为什么,本文就来通俗易懂的讲解一下这么操作的原因。
我们先说两条规则:

  1. 两个对象的hashcode相等,两个对象不一定相等
 Integer a = 97;
 String b = "a";
 // 结果为true
 System.out.println(a.hashCode() == b.hashCode());
 // 结果为false
 System.out.println(a.equals(b));

上面的代码演示大家都知道,a和b的hashcode值是相等的,但是两个值确不相等。

  1. 两个对象equals相等,那么hashcode一定必须相等
public class User implements Serializable {

  private String name;

  private int age;

  public User() {
  }

  public User(String name, int age) {
    this.name = name;
    this.age = age;
  }

  public String getName() {
    return name;
  }

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

  public int getAge() {
    return age;
  }

  public void setAge(int age) {
    this.age = age;
  }

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

我们创建一个实体类User,有两个属性,name和age,然后创建set,get,toString方法,然后再创建一个测试类:

    User user1 = new User();
    user1.setName("a");
    user1.setAge(10);

    User user2 = new User();
    user2.setName("a");
    user2.setAge(10);

    // 结果为false
    System.out.println(user1 == user2);
    // 结果为false
    System.out.println(user1.equals(user2));

根据上面的代码,我们进行解释,创建了user1和user2两个对象,两个对象的属性值完全相等,判断user1 == user2结果为false,判断user1.equals(user2)结果也为false,第一个结果为false能理解,因为在判断两个对象的内存地址是否相等,但是第二个结果为false,这是为什么,带着疑惑,我们点击equals,结论如下:
在这里插入图片描述
原来,Object类的equals方法采用的也是==去判断,那两个对象肯定不相等了,因此我们重写equals方法:

  @Override
  public boolean equals(Object o) {
    if (this == o) {
      return true;
    }
    if (o == null || getClass() != o.getClass()) {
      return false;
    }
    User user = (User) o;
    return age == user.age &&
        Objects.equals(name, user.name);
  }

通过解读equals,我们发现,原来重写后的equals方法是比较两个对象的属性值是否相等,而我们创建的user1和user2的属性值是相等的,因此,重写equals之后user1.equals(user2)的结果为true

 // 重写equals方法后结果为true
 System.out.println(user1.equals(user2));

那么问题来了,重写equals方法为什么还需要重写hashcode方法呢?我们继续讨论,首先我们先判断两个对象的hashcode是否相等:

 // 结果为false
 System.out.println(user1.hashCode() == user2.hashCode());

然后,我创建了一个hashmap,此时user对象重写了equals方法,但是未重写hashcode方法,代码如下:

Map<User, Object> map = new HashMap<>();
map.put(user1, "a");
map.put(user2, "a");
System.out.println(map);

但是我打印出来map的值:
在这里插入图片描述
怎么还是两个,怎么没有去重,两个key的值user1和user2的值是相等的呀,带着疑问,我查看了hashmap源码:
在这里插入图片描述
源码中,除了判断equals是否相等,还根据hash进行了判断,到了此时,应该就明白了,需要重写hashcode方法,因此重写了hashcode方法:

  @Override
  public int hashCode() {

    return Objects.hash(name, age);
  }

通过代码可以看到,hashcode代码是通过属性值来生成 的,然后再次运行刚才的代码:

    Map<User, Object> map = new HashMap<>();
    map.put(user1, "a");
    map.put(user2, "a");
    System.out.println(map);
    // 重写hashcode方法之后结果为true
    System.out.println(user1.hashCode() == user2.hashCode());

结果如下:
在这里插入图片描述
我们可以看到,hashmap已经去重了,两个对象的hashcode值也相等了。
因此结论就是,因为java中map,set等去重时就是根据对象的equqls和hashcode两个值来判断两个对象是否相等,因此重写equals,就必须重写hashcode,即equals判断两个对象相等,那么hashcode也必须保证相等,因此在重写了equals之后也要重写hashcode方法。

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值