equals与hashCode关系梳理
这个并不是一个通用性编程问题,只属于在Java领域内专有问题。
要做好心理准备,这是一个复杂类的问题,要解答这个问题,需要梳理清楚两个函数和其它类之间的关系,并且它们之间的关系有点交织。
equals用法
在 Object 类中还包含了 equals() 方法:
public boolean equals(Object obj) {
return (this == obj);
}
说明:
- == 用于比较
变量
所对应的内存中所存储的数值
是否相同,要比较两个基本类型的数据(注意是基本类型)
或两个引用变量
是否相等,只能用==操作符。
hashCode用法
在 Object 类中还包含了 hashCode() 方法:
public native int hashCode();
请回答,为什么 Object 类需要一个 hashCode() 方法呢?
在 Java 中,hashCode() 方法的主要作用就是为了配合哈希表使用的。
哈希表(Hash Table),也叫散列表,是一种可以通过关键码值(key-value)直接访问的数据结构,它最大的特点就是可以快速实现查找、插入和删除。其中用到的算法叫做哈希,就是把任意长度的输入,变换成固定长度的输出,该输出就是哈希值。像 MD5、SHA1 都用的是哈希算法。
像 Java 中的 HashSet、Hashtable、HashMap 都是基于哈希表的具体实现。其中的 HashMap 就是最典型的代表。
大家想一下,如果没有哈希表,但又需要这样一个数据结构,它里面存放的数据是不允许重复的,它是怎么实现的?
- √ 要不使用 equals() 方法进行逐个比较?这种方案当然是可行的。
但如果数据量特别特别大,采用 equals() 方法进行逐个对比的效率肯定很低很低,总结:能解决,但效率不高。 - √√ 最好的解决方案就是哈希表。总结:不光能解决,还效率不高。
案例说明:
拿 HashMap 来说吧,当我们要在它里面添加对象时,先调用这个对象的 hashCode() 方法,得到对应的哈希值,然后将哈希值和对象一起放到 HashMap 中。当我们要再添加一个新的对象时:
- 获取对象的哈希值;
- 和之前已经存在的哈希值进行比较,如果不相等,直接存进去;
- 如果有相等的,再调用 equals() 方法进行对象之间的比较,如果相等,不存了;
- 如果不等,说明哈希冲突了,增加一个链表,存放新的对象;
- 如果链表的长度大于 8,转为红黑树来处理。
就这么一套下来,调用 equals() 方法的频率就大大降低了。也就是说,只要哈希算法足够的高效,把发生哈希冲突的频率降到最低,哈希表的效率就特别的高。
总结
== 用于比较变量所对应的内存中所存储的数值是否相同,要比较两个基本类型的数据(注意是基本类型)或两个 引用变量是否相等,只能用==操作符。
equals 比较的是值和地址,如果没有重写equals方法,其作用与==相同;
在String类中,重写了equals方法,比较的是值
是否相等;
hashCode用于散列数据结构中的hash值计算;
equals两个对象相等,那hashcode一定相等,hashcode相等,不一定是同一个对象(hash冲突现象);
hashCode 一般与 equals 一起使用,两个对象作「相等」比较时,因判断 hashCode 是判断 equals 的先决条件.
为什么一个类中需要两个比较方法
因为重写的 equals() 里一般比较的比较全面比较复杂,这样效率就比较低,而利用hashCode()进行对比,则只要生成一个 hash 值进行比较就可以了,效率很高,那么 hashCode() 既然效率这么高为什么还要 equals() 呢?
因为 hashCode() 并不是完全可靠,有时候不同的对象他们生成的 hashcode 也会一样(hash冲突),所以 hashCode()只能说是大部分时候可靠,并不是绝对可靠。
equals() 相等的两个对象他们的 hashCode() 肯定相等,也就是用 equals() 对比是绝对可靠的。
为什么重写 equals 方法时必须同时重写 hashCode 方法?
可以先看看Java这B 给出的一些建议,就是事前就规定好了...
public class Object {
/**
* Returns a hash code value for the object. This method is
* supported for the benefit of hash tables such as those provided by
* `java.util.HashMap`.
*
* The general contract of `hashCode` is:
*
* a) Whenever it is invoked on the same object more than once during
* an execution of a Java application, the `hashCode` method must
* consistently return the same integer, provided no information
* used in `equals` comparisons on the object is modified.
* This integer need not remain consistent from one execution of an
* application to another execution of the same application.
*
* b) If two objects are equal according to the `equals(Object)` method,
* then calling the `hashCode` method on each of the two objects must
* produce the same integer result.
*
* c) It is not required that if two objects are unequal according to the
* `equals(Object)` method, then calling the `hashCode` method on each of
* the two objects must produce distinct integer results.
* However, the programmer should be aware that producing distinct integer
* results for unequal objects may improve the performance of hash tables.
*/
@IntrinsicCandidate
public native int hashCode();
/**
* Indicates whether some other object is "equal to" this one.
*
* @apiNote
* It is generally necessary to override the `hashCode` method whenever this
* method is overridden, so as to maintain the general contract for the `hashCode`
* method, which states that equal objects must have equal hash codes.
*/
public boolean equals(Object obj) {
return (this == obj);
}
}
上面介绍了 hashCode 方法注释上列出的三个通用约定,equals 方法的注释上也有这么一句话:「每当重写 equals 方法时,都需要重写 hashCode 方法,这样才没有破坏 hashCode 方法的通用约定,即:两个对象为 Equal 的话(调用 equals 方法为 true), 那么这两个对象分别调用 hashCode 方法也需要返回相同的哈希值」。
所以只重写 equals 方法不重写 hashCode 方法的话,可能会造成两个对象调用 equals 方法为 true,而 hashCode 值不同的情形,这样即可能造成异常的行为。
这个情形是什么?
两个内容相等的Person对象p1和p2的hashCode()不同,是因为在Person类中没有重写hashCode()方法,它们使用的是Object类继承下来的hashCode()方法的默认实现。
在Object类中,hashCode()方法的默认实现是将对象的内存地址值作为哈希码返回。
总结:
就是一个约定而已。也是为了逻辑的自洽。
Reference
Java hashCode方法深入解析
https://www.javabetter.cn/basic-extra-meal/hashcode.html
Java:为什么重写 equals 方法时必须同时重写 hashCode 方法?
https://leileiluoluo.com/posts/always-override-hashcode-when-override-equals.html
equals与hashCode关系梳理的更多相关文章
- 深入理解equals和hashCode关系和区别
为什么要说equals和hashCode这两个东西,一来是因为有不少小伙伴面试时被问过这个东西,二来则是因为如果了解了这两个东西的原理,那么实际的开发过程中,对效率和容错率上还是能帮上很大的忙! 直入 ...
- ==、equals()、hashcode()的关系和区别
==.equals().hashcode()概念 ==:它的作用是判断两个对象的地址是不是相等.即,判断两个对象是不试同一个对象. equals():它的作用也是判断两个对象是否相等.但它一般有两种使 ...
- Java equals 和 hashCode 的这几个问题可以说明白吗?
前言 上一篇文章 如何妙用 Spring 数据绑定? ,灵魂追问 环节留下了一个有关 equals 和 hashcode 问题 .基础面试经常会碰到与之相关的问题,这不是一个复杂的问题,但很多朋友都苦 ...
- Java中equals()和hashCode()的关系以及重写equals()和hashCode()的重要性
转载请注明原文地址:http://www.cnblogs.com/ygj0930/p/6580647.html 一:关系 如果两个对象相等(equal),它们的hashcode一定相同: 如果两个对 ...
- 说说hashCode() 和 equals() 之间的关系?
上一篇关于介绍Object类下的几种方法时面试题时,提到equals()和hashCode()方法可能引出关于“hashCode() 和 equals() 之间的关系?”的面试题,本篇来解析一下这道基 ...
- java学习-- equals和hashCode的关系
hashcode的目的就是在hashset或者hashmap等中比较两个对象相等时,减少equals的使用次数来提高效率 以下为摘录 java中hashcode和equals的区别和联系 HashSe ...
- 关于equals和hashCode
equals()和hashCode()是Object类的两个函数,重要性可见一斑,不过我们平时使用却未必能深入理解他们.本文从java doc触发,讲到它们与哈希表的关系,再到具体的实现,就我目前掌握 ...
- 关于equals、hashcode和集合类的小结
一.首先明确一点:equals()方法和hashcode()方法是Object类里的方法. 查看源码可以知道,在Object类中equals(obj)方法直接返回的是 this == obj 的值. ...
- Java提高篇——equals()与hashCode()方法详解
java.lang.Object类中有两个非常重要的方法: 1 2 public boolean equals(Object obj) public int hashCode() Object类是类继 ...
- java中equals和hashCode方法的解析
解析Java对象的equals()和hashCode()的使用 前言 在Java语言中,equals()和hashCode()两个函数的使用是紧密配合的,你要是自己设计其中一个,就要设计另外一个.在多 ...
随机推荐
- Linux 内核:设备驱动模型(5)平台设备驱动
Linux 内核:设备驱动模型(5)平台设备驱动 背景 我们已经大概熟悉了Linux Device Driver Model:知道了流程大概是怎么样的,为了加深对LDDM框架的理解,我们继续来看pla ...
- Python——比 Seaborn 更好的相关性热力图:Biokit Corrplot
目录 前言:我们需要更好的相关性热力图 对比 Python Seaborn 与 R corrplot 传统的 Seaborn 相关性热力图 R 语言中的相关性热力图 关于 Biokit 简介 库的安装 ...
- NXP i.MX 8M Mini的视频开发案例分享 (下)
本文主要介绍i.MX 8M Mini的视频开发案例,包含基于GStreamer的视频采集.编解码.算法处理.显示以及存储案例,GigE工业相机测试说明,H.265视频硬件解码功能演示说明等. 注:本案 ...
- VUE商城项目 -商品分类功能 - 手稿
- yb课堂 前端项目通用底部选项卡 CommonsFooter 《三十六》
学会看cube-UI文档,并掌握cube-tab-bar开发 前端需求分析 底部导航 首页Banner 首页视频列表 视频详情模块 注册模块 登陆模块 个人信息模块 下单模块 订单列表模块 文档地址: ...
- adorner 使用示例
模块介绍 adorner 是一个现代轻量级的 Python 装饰器辅助模块. 目前该模块仅实现了 4 个类,对应着 4 个功能:制造装饰器.执行计时.函数缓存.捕获重试. 仓库地址:https://g ...
- 【算法】用c#实现计算方法中的经典降幂优化策略,减少计算复杂度
对于给定的数组[x1,x2,x3,-,xn],计算幂的累积:x1^(x2^(x3^(-^xn))的最后一位(十进制)数字. 例如,对于数组[3,4,2],您的代码应该返回1,因为3^(4^2)=3^1 ...
- 使用ES6中Class实现手写PromiseA+,完美通过官方872条用例
目录 Promise出现的原因 myPromise的实现要点 myPromise的实现 myPromise - 实现简单的同步 myPromise - 增加异步功能 myPromise - 链式调用( ...
- [oeasy]教您玩转python - 0005- 勇闯地下城
继续运行 回忆上次内容 上次从1行代码进化到了2行代码 yy p粘贴剪贴板中的内容 将剪贴板中的代码粘贴9999次 9999p 真的实现了万行代码梦 是真·圆梦 没有撒谎的那种 不过圆梦之后多少 ...
- ABC361-C题解
背景 昨天打比赛的时候查了中考分,心快停跳了. 题意 从 \(n\) 个数字中删除 \(k\) 个数字,问剩下的数字中极差的最小值. 分析 首先把这 \(n\) 个数字排序,然后问题就可以转化为求这 ...