【Java】自定义对象作为HashMap的键,同时重写hashCode和equals方法

news2024/9/20 18:53:12

如果要将自定义类的实例 作为HashMap的 键,必须重写hashCode和equals方法

简单版本,看不懂看后面复杂版本解释

在这里插入图片描述

复杂版本解释

当我们用 HashMap存入自定义的类时,如果不重写这个自定义类的equals和hashCode方法,得到的结果会和我们预期的不一样。我们来看 WithoutHashCode.java这个例子。

在其中的第 2到第 18行,我们定义了一个 Key类;在其中的第 3行定义了唯一的一个属性 id。当前我们先注释掉第 9行的 equals方法和第 16行的 hashCode方法。
在这里插入图片描述
在 main函数里的第 22和 23行,我们定义了两个 Key对象,它们的 id都是 1,就好比它们是两把相同的都能打开同一扇门的钥匙。

在第 24行里,我们通过泛型创建了一个HashMap对象。它的键部分可以存放 Key类型的对象,值部分可以存储String类型的对象。

在第 25行里,我们通过 put方法把 k1和一串字符放入到 hm里;而在第 26行,我们想用 k2去从HashMap里得到值;这就好比我们想用 k1这把钥匙来锁门,用 k2来开门。这是符合逻辑的,但从当前结果看, 26行的返回结果不是我们想象中的那个字符串,而是 null。
原因有两个:一是没有重写hashCode方法,二是没有重写equals方法

当我们往HashMap里放 k1时,首先会调用 Key这个类的 hashCode方法计算它的 hash值,随后把 k1放入hash值所指引的内存位置。

关键是我们没有在 Key里定义 hashCode方法。这里调用的仍是 Object类的 hashCode方法(所有的类都是Object的子类),而 Object类的 hashCode方法返回的 hash值其实是 k1对象的 内存地址(假设是1000)。
在这里插入图片描述
如果我们随后是调用 hm.get(k1),那么我们会再次调用 hashCode方法(还是返回 k1的地址 1000),随后根据得到的 hash值,能很快地找到 k1。
但我们这里的代码是 hm.get(k2),当我们调用 Object类的 hashCode方法(因为 Key里没定义)计算 k2的 hash值时,其实得到的是 k2的内存地址(假设是 2000)。由于 k1和 k2是两个不同的对象,所以它们的内存地址一定不会相同,也就是说它们的 hash值一定不同,这就是我们无法用 k2的 hash值去拿 k1的原因。
当我们把第 16和 17行的 hashCode方法的注释去掉后,会发现它是返回 id属性的 hashCode值,这里 k1和 k2的 id都是1,所以它们的 hash值是相等的。
我们再来更正一下存 k1和取 k2的动作。存 k1时,是根据它 id的 hash值,假设这里是 100,把 k1对象放入到对应的位置。而取 k2时,是先计算它的 hash值(由于 k2的 id也是 1,这个值也是 100),随后到这个位置去找。
但结果会出乎我们意料:明明 100号位置已经有 k1,但第 26行的输出结果依然是 null。其原因就是没有重写 Key对象的 equals方法。

下面可能有点绕

HashMap是用链地址法来处理冲突,也就是说,在 100号位置上,有可能存在着多个用链表形式存储的对象。它们通过 hashCode方法返回的 hash值都是100。
在这里插入图片描述
当我们通过 k2的 hashCode到 100号位置查找时,确实会得到 k1。但 k1有可能仅仅是和 k2具有相同的 hash值,但未必和 k2内容相等( k1和 k2两把钥匙未必能开同一扇门),这个时候,就需要调用 Key对象的 equals方法来判断两者是否相等了。
由于我们在 Key对象里没有定义 equals方法,系统就不得不调用 Object类的 equals方法。由于 Object的固有方法是根据两个对象的内存地址来判断,所以 k1和 k2一定不会相等,这就是为什么依然在 26行通过 hm.get(k2)依然得到 null的原因。
为了解决这个问题,我们需要打开第 9到 14行 equals方法的注释。在这个equals方法里,只要两个对象都是 Key类型,且它们的 id相等,它们内容就相等。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/736618.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

3.精通RabbitMQ—基础 RabbitMQ知识、进阶 RabbitMQ知识

本文目录如下: 什么是 RabbitMQ?什么是 消息中间件?RabbitMQ 的应用场景?RabbitMQ 中主要包含哪几个部分? 精通 RabbitMQ,从认识开始 什么是 RabbitMQ? RabbitMQ 整体上是一个 生产者与消费者模型,主要负责 接收、…

Redis的一个大Key

什么是 redis 的大 key? redis 的大 key 不是指存储在 redis 中的某个 key 的大小超过一定的阈值,而是该 key 所对应的 value 过大对于 string 类型来说,一般情况下超过 10KB 则认为是大 key;对于set、zset、hash 等类型来说,一…

无线通信模块接口类型_USB/SDIO/UART接口wifi模块特性

无线通信模块接口,简单来说设备需要与外部设备交换数据的通讯接口,如工程师常提到的USB接口,UART接口,SDIO接口,I2S接口,I2C接口,WAN口,LAN口,SPI接口,以太网接口(RJ-45接口)等。 原文链接:http://www.skylab.com.cn/newsview-2768.html 1、USB接口 USB接口是平…

Git gui教程---第六篇 Git gui的使用 变动,提交

变动,提交 修改TEST.txt的内容,并且点击重新扫描,则TEST文件会出现在未缓存的窗口中 像前面教的一样,缓存后,添加描述后提交,并且打开历史记录可以查看到提交的变动。我这里会新增一个文件并且提交多几次&…

N天爆肝数据库——MySQL(2)

本篇文章,主要对DML DQL进行知识总结和学习。 期待和大家一起学习进步。DML-介绍 DML(数据库操作语言),用来对数据库中表的数据 记录进行增删改操作。 添加数据(INSERT) 修改数据(UPDATE) 删除数据&#…

计算机毕业论文内容参考|基于Java的城乡低保信息管理系统的设计和实现

文章目录 导文摘要:前言:绪论:1课题背景:2国内外现状与趋势:3课题内容:相关技术与方法介绍:系统分析:系统设计:系统实现:系统测试:总结与展望:1本文总结:2后续工作展望:导文 这里是导文计算机毕业论文内容参考|基于Java的城乡低保信息管理系统的设计和实现 摘要:…

C++图形开发(10):移动的方块

文章目录 1.引入2.静止的方块3.移动的方块 1.引入 那么我们今天就来实现一下矩形的移动 注意:本篇文章的内容都是基于此前用空格控制的小球的基础上进行开发的,详见:C图形开发(8):空格键控制小球起跳 先来…

PHP实现微信小程序推送消息至公众号

1、申请微信小程序和公众号必须是同一个主体 2、小程序和公众号必须要认证 3、公众号是服务号,接收消息必须关注公众号 4、公众号后台配置 开通模版服务 申请模版,获取模板消息的ID 关联小程序 获取公众号appid 5、小程序后台获取appid,a…

常用异常检测算法总结记录

这篇博文主要是延续前文系列的总结记录,这里主要是总结汇总日常主流的异常检测算法相关知识内容。 (1)基于统计方法的异常值检测 基于统计方法的异常值检测是一种常用的异常检测算法,它基于样本数据的统计特性来识别与其他样本显…

华为OD机试真题 Java 实现【阿里巴巴找黄金宝箱(I)】【2023 B卷 100分】,附详细解题思路

目录 一、题目描述二、输入描述三、输出描述四、解题思路五、Java算法源码六、效果展示1、输入2、输出3、说明 一、题目描述 一贫如洗的樵夫阿里巴巴在去砍柴的路上,无意中发现了强盗集团的藏宝地,藏宝地有编号从0~N的箱子,每个箱子上面贴有…

如何从一个仪表盘管理多个WordPress网站?

您是否正在寻找一种管理多个WordPress网站的简单方法? 监控多个网站并使其保持更新可能非常耗时。 幸运的是,有几种 WordPress 管理工具可以让您从单个仪表板管理多个 WordPress 网站变得非常容易。这将帮助您节省大量时间,同时使所有 Word…

【Java】堆和优先级队列PriorityQueue

文章目录 一、堆1.1 堆的概念1.2 堆的存储方式1.3 堆的创建1.4 堆的插入与删除1.5 堆的应用场景 二、 优先级队列2.1 什么是优先级队列2.2 堆模拟实现优先级队列 三、Java中的PriorityQueue3.1 PriorityQueue的特性3.2 常用方法 一、堆 1.1 堆的概念 在数据结构中&#xff0c…

Python实现PSO粒子群优化算法优化随机森林回归模型(RandomForestRegressor算法)项目实战

说明:这是一个机器学习实战项目(附带数据代码文档视频讲解),如需数据代码文档视频讲解可以直接到文章最后获取。 1.项目背景 PSO是粒子群优化算法(Particle Swarm Optimization)的英文缩写,是一…

虚拟机的安装

1.选择自定义安装 然后下一步 2.选择稍后安装操作系统,也可以选择2 直接安装 3. 选择Linux和相关版本 4.命名虚拟机 默认都是C盘,修改一下好点 5.分配处理器 看需要同时开几台虚拟机,同时也看一下自己的CPU,处理器默认选1个就行,内核数量 选择为 逻辑处理器数量/同时开的虚…

easyupload

红框位置是上传后的提示 依次尝试上传,发现php,phtml.php3,php5,双写等都不行 .htaccess文件也不行 尝试.php. 绕过 (windows中会把后缀名最后的空格和. 省略,即上传.php.绕过后会变为.php) 加入图片头的php文件也不行 但是加入文…

Gitlab 新项目搭建

文章目录 Gitlab 新项目搭建新建空白项目初始化本地仓库并提交建立本地仓库和远程仓库关系并推送 Gitlab 新项目搭建 新建空白项目 项目名称与本地新建项目名称相同 初始化本地仓库并提交 进入本地项目根目录下,右击 git bash here打开命令窗口;初始化…

【Gradle】Gradle的概述与简单使用

一、概述 1.什么是Gradle? Gradle 是一种构建工具。 Java世界中主要有三大构建工具:Ant、Maven和Gradle。Ant几乎销声匿迹了,常见的就只有Maven和Gradle。 目前市面上Java开发,使用的构建工具基本都是Maven;安卓开…

Zabbix 的使用 续

Zabbix 的使用 续 一、部署 zabbix 代理服务器1.1 环境准备1.2 设置 zabbix 的下载源,安装 zabbix-proxy1.3 部署数据库,要求 MySQL 5.7 或 Mariadb 10.5 及以上版本1.4 导入数据库信息1.5 修改 zabbix-proxy 配置文件1.6 启动 zabbix-proxy1.7 在所有主…

Linux基础工具大全

今天,我带来Linux的基本工具大全。 目录 Linux 软件包管理器 yum软件包的概念查看软件包软件包的名称如何安装软件如何卸载软件更新yum源 Linux编辑器-vimvim的概念vim的几种模式vim的基本操作vim正常模式命令集vim末行模式命令集vim操作总结 Linux编译器-gcc/g的使…

AMCV761、AMC06电液伺服阀放大器

AMCV102、AMC106A、AMCV761、AMC06、AMC16、AMC12、AMC07、AMC13电液伺服阀双喷嘴一档板、干式力矩马达、力反馈八种基本形式,流量范围 1-400L/min、额定油压力 25Mpa 与服油缸或马达一起,用于位置、速度、加速度和力值控制。外置伺服放大器。型有抗污染…