当前位置: 首页 > news >正文

为什么在重写equals方法的时候需要重写hashCode方法

首先

Object.hashCode的通用约定《Effective Java》有一条是():

如果两个对象根据equals(Object)方法是相等的,那么调用这两个对象中任一个对象的hashCode方法必须产生同样的整数结果。

如果只重写了equals方法而没有重写hashCode方法的话,则会违反约定,因为相等的对象必须具有相等的散列码(hashCode)。

其次

其次要明白为什么会有这么个约定,这就要来看下HashMap和HashSet这些基于散列值(hash)实现的类了。


先了解下HashMap的工作原理:

HashMap的主干是一个Entry数组,每一个Entry包含一个key-value键值对。其中的关键是数组下标的处理,数组的下标是根据传入元素的hashCode方法的返回值再和特定的值异或得到的。

得到下标i后,如果table[i]==null,直接新建节点添加,否则,判断table[i]的首个元素是否和传入元素的key一样,如果相同直接覆盖value,这里的相同指的是equals。

如果不相同,判断table[i]是否是红黑树,如果是红黑树,则直接在树中插入键值对。遍历过程中若发现key已经存在直接覆盖value即可。

如果不是红黑树,判断链表长度是否大于8,大于8的话把链表转换为红黑树,在红黑树中执行插入操作,否则进行链表的插入操作。同样,遍历过程中若发现key已经存在直接覆盖value即可。


我们举个小例子来看看,如果重写了equals而不重写hashcode会发生什么样的问题

public class MyTest {
    private static class Person{
        int idCard;
        String name;

        public Person(int idCard, String name) {
            this.idCard = idCard;
            this.name = name;
        }
        @Override
        public boolean equals(Object o) {
            if (this == o) {
                return true;
            }
            if (o == null || getClass() != o.getClass()){
                return false;
            }
            Person person = (Person) o;
            //两个对象是否等值,通过idCard来确定
            return this.idCard == person.idCard;
        }

    }
    public static void main(String []args){
        HashMap<Person,String> map = new HashMap<Person, String>();
        Person person = new Person(1234,"乔峰");
        //put到hashmap中去
        map.put(person,"天龙八部");
        //get取出,从逻辑上讲应该能输出“天龙八部”
        System.out.println("结果:"+map.get(new Person(1234,"萧峰")));
    }
}

实际输出结果:null

如果我们已经对HashMap的原理有了一定了解,这个结果就不难理解了。尽管我们在进行get和put操作的时候,使用的key从逻辑上讲是等值的(通过equals比较是相等的),但由于没有重写hashCode方法,所以put操作时,key(hashcode1)–>hash–>indexFor–>最终索引位置 ,而通过key取出value的时候 key(hashcode2)–>hash–>indexFor–>最终索引位置,由于hashcode1不等于hashcode2,导致没有定位到一个数组位置而返回逻辑上错误的值null(也有可能碰巧定位到一个数组位置,但是也会判断其entry的hash值是否相等。)

所以,在重写equals的方法的时候,必须注意重写hashCode方法,同时还要保证通过equals判断相等的两个对象,调用hashCode方法要返回同样的整数值。而如果equals判断不相等的两个对象,其hashCode可以相同(只不过会发生哈希冲突,应尽量避免)。

通过这个例子,说明了如果不重写hashCode的话,可能导致HashSet、HashMap不能正常的运作。


来自:
java中为什么要重写hashCode和equals? - FreeOC - 博客园
Java集合之一—HashMap_深入浅出学JAVA-CSDN博客_hashmap
【java】HashMap 一遍就懂!!!!_疯-CSDN博客_hashmap

相关文章:

  • 访问Windows网络共享文件的默认账号密码
  • 小米笔记本重装系统后触摸板失灵 的原因之一
  • Error creating bean with name ‘lettuceClientResources‘ defined in class path resource
  • windows彻底永久关闭自动更新的方式
  • springboot2.4之后无需再手动移除spring-boot-configuration-processor
  • Deprecated configuration property ‘spring.resources.static-locations‘
  • 谷歌浏览器地址栏快捷键
  • 断网无法解析服务器DNS地址的解决方法之一
  • ob混淆解密在线工具
  • reres+python 将服务器文件映射到本地
  • 开发者工具一直卡在debugger
  • 鼠标垫防止移位乱跑
  • flash按钮上的字怎么改
  • mac idea搜索classes的快捷键
  • mac打开盖子与合上后外接显示器颜色不一样
  • 【干货分享】SpringCloud微服务架构分布式组件如何共享session对象
  • 2017前端实习生面试总结
  • Date型的使用
  • Docker容器管理
  • flask接收请求并推入栈
  • Laravel深入学习6 - 应用体系结构:解耦事件处理器
  • Node.js 新计划:使用 V8 snapshot 将启动速度提升 8 倍
  • python 装饰器(一)
  • quasar-framework cnodejs社区
  • Sass 快速入门教程
  • Vultr 教程目录
  • 分类模型——Logistics Regression
  • 面试总结JavaScript篇
  • 找一份好的前端工作,起点很重要
  • # Apache SeaTunnel 究竟是什么?
  • #define 用法
  • #我与Java虚拟机的故事#连载13:有这本书就够了
  • (12)Linux 常见的三种进程状态
  • (Matlab)基于蝙蝠算法实现电力系统经济调度
  • (Redis使用系列) SpringBoot中Redis的RedisConfig 二
  • (附源码)spring boot球鞋文化交流论坛 毕业设计 141436
  • (附源码)springboot码头作业管理系统 毕业设计 341654
  • (附源码)springboot学生选课系统 毕业设计 612555
  • (六)c52学习之旅-独立按键
  • (算法)前K大的和
  • (已解决)报错:Could not load the Qt platform plugin “xcb“
  • (转载)hibernate缓存
  • .NET 4 并行(多核)“.NET研究”编程系列之二 从Task开始
  • .net core 依赖注入的基本用发
  • .NET Core中的去虚
  • .NET I/O 学习笔记:对文件和目录进行解压缩操作
  • .NET教程 - 字符串 编码 正则表达式(String Encoding Regular Express)
  • [AIGC] Nacos:一个简单 yet powerful 的配置中心和服务注册中心
  • [android学习笔记]学习jni编程
  • [bzoj2957]楼房重建
  • [C]整形提升(转载)
  • [Firefly-Linux] RK3568修改控制台DEBUG为普通串口UART
  • [html] 动态炫彩渐变背景
  • [Java] 模拟Jdk 以及 CGLib 代理原理
  • [Jquery] 实现温度计动画效果