为什么要重写hashmap中的equals()和hashcode()方法?

本文详细解析了HashMap的工作原理,包括其内部结构、元素添加流程及如何避免重复。特别强调了equals和hashCode方法的重要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

首先说一下,hashmap集合的本质,他的底层是一个一维数组,数组中的每个元素都是一个单链表,每个单链表都有节点node,每个节点都包含四个元素:
hash;
final K key;
V value;
Node<K,V> next; 看图:
hashmap的k部分其实存储在hashset集合;我们知道hashset集合是不能重复的,如果存放相同的值,后一个会把前一个覆盖掉,既然这样,也就是说hashmap也不能重复。

在这里插入图片描述

说一下hashmap的添加元素的原理:首先,你放进去一个键值对,假如是<1,“user>”,首先会调用对象1(Integer类型)的hashcode方法,获得到hashcode值,然后底层经过哈希算法转换成数组下标,假如数组下标是1,那么首先会查看下标1这里是不是空,如果是空,会放进去,不是空,就拿k与其中的(单链表种第一个节点)的k用equals比较(比较的是内容,所以一定要重写equals),如果比较到最后也没有返回true(都返回false),就加入到单链表末尾;如果中途返回了返回了true,那么这个k将会被覆盖。

重点来了

假设现在有如下代码:

在这里插入代码片
public class ColletionTest01 {
    public static void main(String[] args) {
        HashSet hashSet=new HashSet();
        user user1=new user("luo");
        user user2=new user("luo");
        System.out.println(user1.equals(user2));
        hashSet.add(user1);
        hashSet.add(user2);
        System.out.println(hashSet.size());
    }
}

class  user{
private String anme;

    public user(String anme) {
        this.anme = anme;
    }
    public boolean equals(Object obj) {
        if(obj==null || !(obj instanceof user)) return false;
        if(obj==this) return true;
        user u=(user) obj;
        return this.anme.equals(u.anme);
    }
}

运行结果:在这里插入图片描述
显然重写了user类的equals方法,按理说答案因该输出1(因为hashset不允许有重复的)但是却输出了2。
上面代码是hashset,因为对于hashmap来说,你放进去的k部分就是hashset,上面提到了。
原因:仅仅重写了equals方法,没有重写hashcode方法。首先两个对象调用hashcode方法,但是得到了不同的值,k部分转化为数组下标,既然数组下标都不相同了,那么两个对象肯定全放进去。都放进去肯定是不行的,因为hashmap不能重复!!

**
解决办法:将equals方法和hashcode方法都重写,这样的话,就拿上面的例子来说,重写过后的hashcode方法,如果k部分内容相同的话,就会转化为相同的数组下标,user1和user2对象的内容相同,他们俩在同一个数组下标上,也就是说他们俩在同一个单链表上,之后会调用equals方法进行内容的比较,当把user1放进去后,在放进user2过程中,会把user1覆盖掉,因为他们俩内容相同,equals方法重写过后,比较的是内容**

equals和hashcode都重写后的代码:

在这里插入代码片
public class ColletionTest01 {
    public static void main(String[] args) {
        HashSet hashSet=new HashSet();
        user user1=new user("luo");
        user user2=new user("luo");
        System.out.println(user1.equals(user2));
        hashSet.add(user1);
        hashSet.add(user2);
        System.out.println(hashSet.size());

    }
}

class  user{
private String anme;

    public user(String anme) {
        this.anme = anme;
    }

    @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(anme, user.anme);
    }

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

结果:
在这里插入图片描述
重写过后就对了,有重复的会覆盖掉!
补充其实重写后的hashcode方法,里面调用了hash方法,参数是k部分的内容,下面是调用hash方法的源代码:

在这里插入代码片
 public static int hash(Object... values) {
        return Arrays.hashCode(values);
    }

可以看出来,valuse就是你传入的参数,如果k部分相同,就证明你传进去的values相同,那么得到的hashcode也会相同,转化的数组下标也相同,这样就不会有重复的了!

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Java学习使我快乐

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值