首页 > 其他分享 >equals与hashCode关系梳理

equals与hashCode关系梳理

时间:2024-08-26 11:38:26浏览次数:5  
标签:重写 Object 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 中。当我们要再添加一个新的对象时:

  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

标签:重写,Object,equals,hashCode,哈希,方法,梳理
From: https://www.cnblogs.com/mysticbinary/p/18128029

相关文章

  • Ansible-playbook 应用梳理
    前面已经介绍过Ansible的安装配置及常见模块的使用--《Linux下使用Ansible处理批量操作》Palybook简介palybook是由一个或多个paly组成的列表,play的主要功能在于将事先归并为一组的主机装扮成事先通过ansible中的task定义好的角色。从根本上来讲,所谓task无非是调用ansible......
  • 华为流程框架梳理及实施
             获取全部108页完成PPT材料,见下图 ......
  • 电磁介质 知识梳理
    1.电介质\[\def\oiint{{\bigcirc}\kern-11.5pt{\int}\kern-6.5pt{\int}}\def\oiiint{{\bigcirc}\kern-12.3pt{\int}\kern-7pt{\int}\kern-7pt{\int}}\]1.1极化的微观机制在一类电介质中,当外电场不存在时,电介质分子的正负电荷中心是重合的,这类分子叫做无极分子;另外一类电介质......
  • Nginx: 体系化知识点梳理
    概述我们需要对Nginx要有体系化的一个认识对Nginx自身来说,它是作为一个中间件的,只要是中间件,它必然会涉及到前端和后端对于Nginx来说,它是需要协调整个前后端的一个组件那对于中间件来,我们要理解整个外部系统前端和后端是如何进行交互的我们一个用户请求过来以后,......
  • Nginx: 配置项之main段核心参数用法梳理
    概述我们了解下配置文件中的一个全局段,有哪些配置参数,包括后面的events字段,有哪些配置参数这里面也有一些核心参数,对于我们Nginx运行的性能也是有很重要的帮助我们现在首先关注整个main段的一个核心参数用法所谓main段,是指在nginx.conf配置文件中,除了有events......
  • 一次实战压测流程及问题梳理
    1、背景及目的在动手之前,先要想清楚我们期望从压测中获取的价值是什么。这次压测的背景,主要是为了应对旺季到来,避免旺季的大量流量和高并发造成服务不可用,提升稳定性。而在稳定性建设中,也会从事前、事中及事后来看,包含的维度包含风险识别、监控告警、应急流程及故障复盘等不同的......
  • [C语言]-基础知识点梳理-动态内存管理
    前言各位师傅大家好,我是qmx_07,今天给大家讲解动态内存管理的相关知识,下一章节更新文件管理部分的知识点为什么要进行动态内存分配intval=20;//在栈空间上开辟四个字节chararr[10]={0};//在栈空间上开辟10个字节的连续空间上述的开辟空间的⽅式有两个特点:空......
  • 知识图谱——Gephi梳理学术脉络
    Gephi是一款开源的图形可视化和分析工具,它主要用于处理和可视化大型网络数据集。虽然Gephi主要用于图形分析,但它也可以作为一种有用的工具来辅助学术写作,尤其是在需要分析和展示研究领域内的网络关系时。下面我将详细介绍如何使用Gephi进行学术写作,并给出一个具体的例子。Geph......
  • 知识图谱——CiteSpace梳理学术脉络
    CiteSpace是一款强大的可视化分析软件,专门用于分析和可视化科学文献中的引文网络,以帮助识别科学领域的知识结构、研究前沿和发展趋势。下面我将详细介绍如何使用CiteSpace进行学术脉络梳理,并给出一个具体的例子。CiteSpace简介CiteSpace是一款免费的软件,它基于Java开发,可以用......
  • 基于v4l2框架应用层的摄像头梳理
    ------------恢复内容开始------------#1.官方的测试程序###代码路径media/v4l/capture.c点击查看代码/**V4L2videocaptureexample**Thisprogramcanbeusedanddistributedwithoutrestrictions.#**ThisprogramisprovidedwiththeV4L2A......