[Java]重写equals为什么要重写hashcode???配合HashMap源码一起理解

1、什么是hashCode

hashCode()是Object定义的方法,它将返回一个整型值,这个方法通常用来将对象的内存地址转换为整数之后返回,它存在的价值是为Hash容器处理数据时提供支持,Hash容器可以根据hashCode定位需要使用的对象,也可以根据hashCode来排除2个不相同的对象,即:hashCode不同,则视为2个对象不同。

2、为什么要有hashCode

哈希码主要在哈希表这类集合映射的时候用到,哈希表存储的是键值对(key-value),它的特点是:能根据“键”快速的映射到对应的“值”。这其中就利⽤到了哈希码。
例如 HashMap 怎么把 key 映射到对应的 value 上呢?用的就是哈希取余法,也就是拿哈希码和存储元素的数组的长度取余,获取 key 对应的 value 所在的下标位置。

3、为什么重写 equals 时必须重写 hashCode 方法?

举例说明:

新建一个User类

public class User {

    private String name;

    private Integer age;

    public String getName() {
        return name;
    }

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

    public Integer getAge() {
        return age;
    }

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

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

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

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

上述代码中的equals和hashCode是还没有进行重写的默认原始方法,可以看出,如果没有重写equals方法,那么两个对象进行equals比较时,只有当两个对象的所有属性都相等时,才会认为两个对象相等。

public class Test {
    public static void main(String[] args) {
        User user =new User();
        user.setName("yhz");
        user.setAge(18);

        User user1 = new User();
        user1.setAge(19);
        user1.setName("yhz");

        System.out.println(user.equals(user1));
    }
}

在这里插入图片描述

现在只改一下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 Objects.equals(name, user.name);
    }

现在只要两个User对象的name相同,那么就认为这两个User对象相同。
在这里插入图片描述
现在,我new一个HashSet集合,将两个user对象add进去,大家猜猜set里面有几个User

		User user =new User();
        user.setName("yhz");
        user.setAge(18);

        User user1 = new User();
        user1.setAge(19);
        user1.setName("yhz");
			
		System.out.println(user.equals(user1));
		
		Set<User>set= new HashSet();
        set.add(user);
        set.add(user1);
        System.out.println(set);

公布答案:
set里面有两个user对象,欸?上面user.equals(user1)明明返回的是true,我们也知道,Set的特点是不重复,那为什么还会出现两个呢?

原因是: HashSet、HashMap集合在添加元素的时候,用哈希取余法,也就是拿hashCode和存储元素的数组的长度取余,获取 key 对应的 value 所在的下标位置。如果获取到的下标位置上已经存在元素,则认为产生了哈希碰撞(hashCode() 所使用的散列算法也许刚好会让多个对象传回相同的散列值。)再拿新添元素(新的)与当前位置上的元素(旧的)进行equals比较,如果返回true就用新的替换旧的。如果返回false就添加到该位置下面的链表尾或红黑树上。而如果没有发生哈希碰撞,也就间接说明两个对象不相等。然而我们上面只是重写了equals方法(只比较name是否相同),而hashCode返回的还是name和age组合成的数组的hashCode,所以虽然equals返回true,但是两个对象的hashCode不一样,set里存在两个user而不是一个。
HashMap的put过程源码讲解在这里
hashCode() 的默认行为是对堆上的对象产⽣独特值。如果没有重写 hashCode() ,则该 class 的两个对象⽆论如何都不会相等(即使这两个对象指向相同的数据)

现在重写hashCode方法

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

再看一下执行结果:
在这里插入图片描述
这回set里只有一个user了。
所以一定记住,重写 equals 方法时必须重写 hashCode 方法。

好了,到这里希望你已经理解重写equals为什么要重写hashcode了😀

4、易错点

  1. hashCode相等,两个字符串不一定相等。
  2. hashCode相等,这两个对象不一定相等。
  3. hashCode不等,这两个对象一定不相等。
  4. 如果两个对象分别调⽤ equals 方法都返回 true,则这两个对象一定相等。
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值