深入理解equals和hashCode关系和区别

2023-05-16

深入理解equals和hashCode关系和区别

  • 直入主题:
    • 区别:
      • 1.他们判断对象相同的方式不一样:
      • 2.他们判断对象是否相等的准确率不一样:
    • 改写equals时总是要改写hashcode
    • 分享一波:程序员赚外快-必看的巅峰干货

为什么要说equals和hashCode这两个东西,一来是因为有不少小伙伴面试时被问过这个东西,二来则是因为如果了解了这两个东西的原理,那么实际的开发过程中,对效率和容错率上还是能帮上很大的忙!

直入主题:

很多人把他们放在一起比较,那我们首先要想到的是,他们肯定有大致相同的作用,和一些细小的区别。
先说说他们相同的作用:equals和hashCode方法都是用来判断两个对象的值是否相等,请记住这里说的相等仅仅说的是两个对象的值,和他们的引用无关

区别:

1.他们判断对象相同的方式不一样:

2.他们判断对象是否相等的准确率不一样:

为啥这样说,因为hashCode有极小概率会判断错,而equals的判断结果是百分百正确的

相信看到这里已经有朋友有疑问了,既然hashCode方法不能准确判断,那我们为什么还要用它?哈哈哈,因为我们无法忍受丢弃他的另一个优点,就是效率高,接着往下看,我们慢慢捋一捋。

先说上面的第一点:判断对象的相等的方式不一样

1.equals:重写的equals方法,比如String 的equals方法,如图:
在这里插入图片描述
他最终的目的循环判断两个对象的每一个字符是否相等,所有字符全部对应相等,那他们的值肯定也就相等了,这是equals的判断方法

hashCode的判断方法:hashCode是通过用hash算法来计算具体对象实例,得到斌返回一个hashcode值。通过比较hashcode值是否相等来判断两个对象是否相等,

相信大家看到这里是已经有点懵逼了,别急,接下来具体讲讲他的原理:

以java.lang.Object来理解,JVM每new一个Object,它都会将这个Object丢到一个Hash哈希表中去,这样的话,下次做Object的比较或者取这个对象的时候,它会根据对象的hashcode再从Hash表中取这个对象。这样做的目的是提高取对象的效率。具体过程是这样:

  1. new Object(),JVM根据这个对象的Hashcode值,放入到对应的Hash表对应的Key上,如果不同的对象确产生了相同的hash值,也就是发生了Hash key相同导致冲突的情况,那么就在这个Hash key的地方产生一个链表,将所有产生相同hashcode的对象放到这个单链表上去,串在一起。
  2. 比较两个对象的时候,首先根据他们的hashcode去hash表中找他的对象,当两个对象的hashcode相同,那么就是说他们这两个对象放在Hash表中的同一个key上,那么他们一定在这个key上的链表上。那么此时就只能根据Object的equal方法来比较这个对象是否equal。当两个对象的hashcode不同的话,肯定他们不能equal.

可能经过上面理论的讲一下大家都迷糊了,我也看了之后也是似懂非懂的。下面我举个例子详细说明下。

list是可以重复的,set是不可以重复的。那么set存储数据的时候是怎样判断存进的数据是否已经存在。使用equals()方法呢,还是hashcode()方法。
  假如用equals(),那么存储一个元素就要跟已存在的所有元素比较一遍,比如已存入100个元素,那么存101个元素的时候,就要调用equals方法100次。
  
  但如果用hashcode()方法的话,他就利用了hash算法来存储数据的。
这样的话每存一个数据就调用一次hashcode()方法,得到一个hashcode值及存入的位置。如果该位置不存在数据那么就直接存入,否则调用一次equals()方法,不相同则存,相同不存。这样下来整个存储下来不需要调用几次equals方法,虽然多了几次hashcode方法,但相对于前面来讲效率高了不少。

上面开始的时候我着重说了重写的equals方法,为什么要重写呢?

因为Object的equal方法默认是两个对象的引用的比较,意思就是指向同一内存,地址则相等,否则不相等;如果你现在需要利用对象里面的值来判断是否相等,则重载equal方法。

说道这个地方我相信很多人会有疑问,相信大家都被String对象的equals()方法和"= ="纠结过一段时间,当时我们知道String对象中equals方法是判断值的,而= =是地址判断。
那照这么说equals怎么会是地址的比较呢?

那是因为实际上JDK中,String、Math等封装类都对Object中的equals()方法进行了重写。
  我们先看看Object中equals方法的源码:
  在这里插入图片描述
  我们都知道所有的对象都拥有标识(内存地址)和状态(数据),同时“==”比较两个对象的的内存地址,所以说使用Object的equals()方法是比较两个对象的内存地址是否相等,即若object1.equals(object2)为true,则表示equals1和equals2实际上是引用同一个对象。虽然有时候Object的equals()方法可以满足我们一些基本的要求,但是我们必须要清楚我们很大部分时间都是进行两个对象的比较,这个时候Object的equals()方法就不可以了,所以才会有String这些类对equals方法的改写,依次类推Double、Integer、Math。。。。等等这些类都是重写了equals()方法的,从而进行的是内容的比较。希望大家不要搞混了。

改写equals时总是要改写hashcode

java.lnag.Object中对hashCode的约定:

  1. 在一个应用程序执行期间,如果一个对象的equals方法做比较所用到的信息没有被修改的话,则对该对象调用hashCode方法多次,它必须始终如一地返回同一个整数。
  2. 如果两个对象根据equals(Object o)方法是相等的,则调用这两个对象中任一对象的hashCode方法必须产生相同的整数结果。
  3. 如果两个对象根据equals(Object o)方法是不相等的,则调用这两个对象中任一个对象的hashCode方法,不要求产生不同的整数结果。但如果能不同,则可能提高散列表的性能。
    根据上一个问题,实际上我们已经能很简单的解释这一点了,比如改写String中的equals为基于内容上的比较而不是内存地址的话,那么虽然equals相等,但并不代表内存地址相等,由hashcode方法的定义可知内存地址不同,没改写的hashcode值也可能不同。所以违背了第二条约定。
    又如new一个对象,再new一个内容相等的对象,调用equals方法返回的true,但他们的hashcode值不同,将两个对象存入HashSet中,会使得其中包含两个相等的对象,因为是先检索hashcode值,不等的情况下才会去比较equals方法的。

原创文章,转载请标明出处

分享一波:程序员赚外快-必看的巅峰干货

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

深入理解equals和hashCode关系和区别 的相关文章

随机推荐

  • 快速解决 MacOS 启动台程序删除之后图标仍存在显示问号的问题

    解决 第一个方案是更新 sqlite 数据库 但是这个方案会改动启动台图标的顺序 还是不推荐的 第二个方案最近摸索出来的 直接把图标拖拽到废纸篓即可 怒赞
  • Jekyll博客中添加分类与多目录存放博客的方法

    categories Frontend tags Frontend HTML 写在前面 最近发现一个问题 博客数量越来越多了 都放在 posts下实在是有点不方便 于是想着分个类 Google 了一圈 找到了一篇不错的博客 如下 Jekyl
  • 推荐三本wpf的书

    1 葵花宝典WPF 2 WPF深入浅出 3 WPF编程宝典 个人粗略浏览了一遍 xff0c 第二本收获比较多 xff0c 第三本比较全面 xff0c 第一本相对来说没那么枯燥 xff0c 前两本我有pfd的资源文件 xff0c 需要的留言我
  • C++实现A钱买A鸡问题

    总时间限制 10000ms 单个测试点时间限制 1000ms 内存限制 131072kB 描述 A钱买A鸡 的问题 xff1a 3文钱可以买1只公鸡 xff0c 2文钱可以买1只母鸡 xff0c 1文钱可以买3只小鸡 xff0c 要用A文钱
  • equals 和 hashCode 的区别

    1 equals 和 hashCode 的区别 equals 和 hashcode 这两个方法都是从 Object 类中继承过来的 hashCode xff1a 计算出对象实例的哈希码 xff0c 并返回哈希码 xff0c 又称为散列函数
  • (踩坑)windows下的linux子系统迁移至非系统盘

    踩坑如下 xff1a 先在微软应用市场下载linux然后安装完 xff0c 再做目录链接会出现linux启动失败问题 先做目录链接会导致应用市场下载linux失败 xff0c 如下图 xff1a 正确操作如下 xff1a 注意两个路径 xf
  • 2、Zabbix 添加主机和监控项

    一 修改用户密码 1 zabbix默认会监控zabbix server本机 xff0c 如果不想监控可以在 xff08 配置 主机 xff09 里禁用掉 2 zabbix的用户都属于某个用户组 xff0c 而权限的控制都是通过用户组的 xf
  • Ubuntu进入文件夹路径及查看文件夹目录

    在Ubuntu中 xff0c 我们进入了一个文件夹 xff0c 如何看这个文件夹此时的路径呢 xff1f 通过Ctrl 43 L 可以看到路径 xff0c 然后Ctrl 43 C复制路径 再通过命令行中cd 路径 进入刚刚的文件夹 如何查看
  • WebService实例

    一 发布webservice服务 1 编写服务接口 package com nari test webservice import javax jws WebMethod import javax jws WebParam import j
  • C#使用selenium写爬虫提高速度的关键

    这段时间一直在搞爬虫 xff0c 学了一段时间之后 xff0c 最后还是使用的selenium模拟浏览器来进行爬取 就来记录一下自己踩的坑 一开始在网上找提升selenium爬虫速度的方法 xff0c 都是说什么多线程 xff0c 关闭图片
  • coreldraw2022直装版下载 永久免费使用 附安装教程( 仅限 win 10 用户 )

    CorelDRAW2022又被大家伙简称为cdr2022 xff0c 这是由加拿大Corel公司制作推出的一款老牌图形平面设计软件 xff0c 当然虽然该软件是好早之前就有了 xff0c 但是本次小编要介绍的是该系列最新的2022版本 在该
  • win10/11下WSL 图形界面安装配置指南

    win10 11下WSL 图形界面安装配置指南 一 首先安装WSL xff08 这里安装的是Ubuntu 20 04 LTS xff09 二 MobaXterm安装 xff1a 神器MobaXterm xff0c 能同时支持XShell和X
  • WSL安装迁移以及可能会遇到的问题

    可能需要的命令 xff1a 查看ubuntu版本 xff1a lsb release a 修改文件参数 xff1a G WSL grant 34 rx OI CI F 34 查看一下wsl的版本 xff0c PowerShell 命令行并输
  • namespace “std“没有成员“function“

    添加头文件 include lt functional gt 确保C 43 43 版本为C 43 43 11或更高
  • Verilog 有限状态机

    状态机基本概念 状态机 xff0c 全称是有限状态机 xff08 Finite State Machine xff0c 缩写为FSM xff09 xff0c 是一种在有限个状态之间按一定规律转换的时序电路 xff0c 可以认为是组合逻辑和时
  • 深度学习之神经网络(二)

    文章目录 深度学习之神经网络 xff08 二 xff09 一 神经网络起源 xff1a 线性回归 xff08 一 xff09 概念 xff08 二 xff09 一个线性回归问题 xff08 三 xff09 优化方法 xff1a 梯度下降 二
  • 怎样将github上的代码下载到本地并运行?

    一 直接下载 点击右下角的Download Zip xff0c 可以直接下载项目的压缩包到你的电脑上 xff08 比如我先在github上搜索了一个vue 的项目 xff09 二 通过git clone下载 PS 使用git clone下载
  • kali搭建php环境

    service apache2 start service mysql start 然后再 var wwwxi下面直接写就好了 做个小demo吧 lt php servername 61 34 localhost 34 username 6
  • linux忽略依赖强制安装软件

    1 强制安装 deb文件 dpkg i force overwrite xxx deb 强制安装软件 dpkg i force all xxx deb 不顾一切的强制安装软件 2 强制安装 rpm文件 span class token fu
  • 深入理解equals和hashCode关系和区别

    深入理解equals和hashCode关系和区别 直入主题 xff1a 区别 xff1a 1 他们判断对象相同的方式不一样 xff1a 2 他们判断对象是否相等的准确率不一样 xff1a 改写equals时总是要改写hashcode分享一波