这个并不是一个通用性编程问题,只属于在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 中。当我们要再添加一个新的对象时:

  1. 获取对象的哈希值;
  2. 和之前已经存在的哈希值进行比较,如果不相等,直接存进去;
  3. 如果有相等的,再调用 equals() 方法进行对象之间的比较,如果相等,不存了;
  4. 如果不等,说明哈希冲突了,增加一个链表,存放新的对象;
  5. 如果链表的长度大于 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关系梳理的更多相关文章

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

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

  2. ==、equals()、hashcode()的关系和区别

    ==.equals().hashcode()概念 ==:它的作用是判断两个对象的地址是不是相等.即,判断两个对象是不试同一个对象. equals():它的作用也是判断两个对象是否相等.但它一般有两种使 ...

  3. Java equals 和 hashCode 的这几个问题可以说明白吗?

    前言 上一篇文章 如何妙用 Spring 数据绑定? ,灵魂追问 环节留下了一个有关 equals 和 hashcode 问题 .基础面试经常会碰到与之相关的问题,这不是一个复杂的问题,但很多朋友都苦 ...

  4. Java中equals()和hashCode()的关系以及重写equals()和hashCode()的重要性

    转载请注明原文地址:http://www.cnblogs.com/ygj0930/p/6580647.html  一:关系 如果两个对象相等(equal),它们的hashcode一定相同: 如果两个对 ...

  5. 说说hashCode() 和 equals() 之间的关系?

    上一篇关于介绍Object类下的几种方法时面试题时,提到equals()和hashCode()方法可能引出关于“hashCode() 和 equals() 之间的关系?”的面试题,本篇来解析一下这道基 ...

  6. java学习-- equals和hashCode的关系

    hashcode的目的就是在hashset或者hashmap等中比较两个对象相等时,减少equals的使用次数来提高效率 以下为摘录 java中hashcode和equals的区别和联系 HashSe ...

  7. 关于equals和hashCode

    equals()和hashCode()是Object类的两个函数,重要性可见一斑,不过我们平时使用却未必能深入理解他们.本文从java doc触发,讲到它们与哈希表的关系,再到具体的实现,就我目前掌握 ...

  8. 关于equals、hashcode和集合类的小结

    一.首先明确一点:equals()方法和hashcode()方法是Object类里的方法. 查看源码可以知道,在Object类中equals(obj)方法直接返回的是  this == obj 的值. ...

  9. Java提高篇——equals()与hashCode()方法详解

    java.lang.Object类中有两个非常重要的方法: 1 2 public boolean equals(Object obj) public int hashCode() Object类是类继 ...

  10. java中equals和hashCode方法的解析

    解析Java对象的equals()和hashCode()的使用 前言 在Java语言中,equals()和hashCode()两个函数的使用是紧密配合的,你要是自己设计其中一个,就要设计另外一个.在多 ...

随机推荐

  1. Linux 内核:设备驱动模型(5)平台设备驱动

    Linux 内核:设备驱动模型(5)平台设备驱动 背景 我们已经大概熟悉了Linux Device Driver Model:知道了流程大概是怎么样的,为了加深对LDDM框架的理解,我们继续来看pla ...

  2. Python——比 Seaborn 更好的相关性热力图:Biokit Corrplot

    目录 前言:我们需要更好的相关性热力图 对比 Python Seaborn 与 R corrplot 传统的 Seaborn 相关性热力图 R 语言中的相关性热力图 关于 Biokit 简介 库的安装 ...

  3. NXP i.MX 8M Mini的视频开发案例分享 (下)

    本文主要介绍i.MX 8M Mini的视频开发案例,包含基于GStreamer的视频采集.编解码.算法处理.显示以及存储案例,GigE工业相机测试说明,H.265视频硬件解码功能演示说明等. 注:本案 ...

  4. VUE商城项目 -商品分类功能 - 手稿

  5. yb课堂 前端项目通用底部选项卡 CommonsFooter 《三十六》

    学会看cube-UI文档,并掌握cube-tab-bar开发 前端需求分析 底部导航 首页Banner 首页视频列表 视频详情模块 注册模块 登陆模块 个人信息模块 下单模块 订单列表模块 文档地址: ...

  6. adorner 使用示例

    模块介绍 adorner 是一个现代轻量级的 Python 装饰器辅助模块. 目前该模块仅实现了 4 个类,对应着 4 个功能:制造装饰器.执行计时.函数缓存.捕获重试. 仓库地址:https://g ...

  7. 【算法】用c#实现计算方法中的经典降幂优化策略,减少计算复杂度

    对于给定的数组[x1,x2,x3,-,xn],计算幂的累积:x1^(x2^(x3^(-^xn))的最后一位(十进制)数字. 例如,对于数组[3,4,2],您的代码应该返回1,因为3^(4^2)=3^1 ...

  8. 使用ES6中Class实现手写PromiseA+,完美通过官方872条用例

    目录 Promise出现的原因 myPromise的实现要点 myPromise的实现 myPromise - 实现简单的同步 myPromise - 增加异步功能 myPromise - 链式调用( ...

  9. [oeasy]教您玩转python - 0005- 勇闯地下城

     ​ 继续运行 回忆上次内容 上次从1行代码进化到了2行代码 yy p粘贴剪贴板中的内容 将剪贴板中的代码粘贴9999次 9999p 真的实现了万行代码梦 是真·圆梦 没有撒谎的那种 不过圆梦之后多少 ...

  10. ABC361-C题解

    背景 昨天打比赛的时候查了中考分,心快停跳了. 题意 从 \(n\) 个数字中删除 \(k\) 个数字,问剩下的数字中极差的最小值. 分析 首先把这 \(n\) 个数字排序,然后问题就可以转化为求这 ...