为什么重写equals还要重写hashcode方法

news2024/12/23 8:38:29

目录

    • equals方法
    • hashCode方法
    • 为什么要一起重写?
    • 总结
    • 面试如何回答

重写 equals 时为什么一定要重写 hashCode?要想了解这个问题的根本原因,我们还得先从这两个方法开始说起。

以下是关于hashcode的一些规定:

  • 两个对象相等,hashcode一定相等
  • 两个对象不等,hashcode不一定不等
  • hashcode相等,两个对象不一定相等
  • hashcode不等,两个对象一定不等

equals方法

Object类默认的equals比较规则就是比较两个对象的内存地址
equals 方法的实现源码如下:
在这里插入图片描述
通过以下示例,就可以说明这个问题:

public class Test1 {
    public static void main(String[] args) {
        People people1 = new People("lisi", 14);
        People people2 = new People("lisi", 14);
        System.out.println(people1.equals(people2));
    }
}
class People{
    private String name;
    private Integer age;
    public People(String name, Integer age) {
        this.name = name;
        this.age = age;
    }
}

以上程序的执行结果,如下图所示
在这里插入图片描述
因此通常情况下,我们要判断两个对象是否相等,一定要重写 equals 方法,这就是为什么要重写 equals 方法的原因。

hashCode方法

Object 的 hashcode 方法是本地方法,也就是用 c 或 c++ 实现的,该方法直接返回对象的内存地址,让后再转换整数。
hashCode 在 Object 中的源码如下:
在这里插入图片描述
相等的值 hashCode 一定相同的示例:

public class Test1 {
    public static void main(String[] args) {
        String s1 = "abc";
        String s2 = "abc";
        System.out.println("s1 hashCode:" + s1.hashCode());
        System.out.println("s2 hashCode:" + s2.hashCode());
    }
}

以上程序的执行结果,如下图所示:
在这里插入图片描述
不同的值 hashCode 也有可能相同的示例:

public class Test1 {
    public static void main(String[] args) {
        String s1 = "Aa";
        String s2 = "BB";
        System.out.println("s1 hashCode:" + s1.hashCode());
        System.out.println("s2 hashCode:" + s2.hashCode());
    }
}

以上程序的执行结果,如下图所示:
在这里插入图片描述

为什么要一起重写?

为了解释这个问题,我们需要从下面的这个例子入手。
Set 正常使用
Set 集合是用来保存不同对象的,相同的对象就会被 Set 合并,最终留下一份独一无二的数据。
它的正常用法如下:

public class Test1 {
    public static void main(String[] args) {
        Set<String> set = new HashSet();
        set.add("lisi");
        set.add("lisi");
        set.add("zhangsan");
        set.add("zhangsan");
        System.out.println("Set 集合长度:" + set.size());
        // 打印 Set 中的所有元素
        set.forEach(System.out::println);
    }
}

以上程序的执行结果,如下图所示:
在这里插入图片描述
从上述结果可以看出,重复的数据已经被 Set 集合“合并”了,这也是 Set 集合最大的特点:去重。
Set 集合的异常
如果我们在 Set 集合中存储的是,只重写了 equals 方法的自定义对象时,有趣的事情就发生了

public class Test1 {
    public static void main(String[] args) {
        Set<People> set = new HashSet();
        set.add(new People("lisi", 14));
        set.add(new People("lisi", 14));
        System.out.println("Set 集合长度:" + set.size());
        // 打印 Set 中的所有元素
        set.forEach(System.out::println);
    }
}
class People{
    private String name;
    private Integer age;
    public People(String name, Integer age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return "People{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        People people = (People) o;
        return Objects.equals(name, people.name) && Objects.equals(age, people.age);
    }
}

以上程序的执行结果,如下图所示:
在这里插入图片描述
从上述代码和上述图片可以看出,即使两个对象是相等的,Set 集合竟然没有将二者进行去重与合并。这就是重写了 equals 方法,但没有重写 hashCode 方法的问题所在。
解决异常
为了解决上面的问题,我们尝试在重写 equals 方法时,把 hashCode 方法也一起重写了,实现代码如下:

public class Test1 {
    public static void main(String[] args) {
        Set<People> set = new HashSet();
        set.add(new People("lisi", 14));
        set.add(new People("lisi", 14));
        System.out.println("Set 集合长度:" + set.size());
        // 打印 Set 中的所有元素
        set.forEach(System.out::println);
    }
}
class People{
    private String name;
    private Integer age;
    public People(String name, Integer age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return "People{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        People people = (People) o;
        return Objects.equals(name, people.name) && Objects.equals(age, people.age);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, age);
    }
}

在这里插入图片描述
原因分析
出现以上问题的原因是,如果只重写了 equals 方法,那么默认情况下,Set 进行去重操作时,会先判断两个对象的 hashCode 是否相同,此时因为没有重写 hashCode 方法,所以会直接执行 Object 中的 hashCode 方法,而 Object 中的 hashCode 方法对比的是两个不同引用地址的对象,所以结果是 false,那么 equals 方法就不用执行了,直接返回的结果就是 false:两个对象不是相等的,于是就在 Set 集合中插入了两个相同的对象。
但是,如果在重写 equals 方法时,也重写了 hashCode 方法,那么在执行判断时会去执行重写的 hashCode 方法,此时对比的是两个对象的所有属性的 hashCode 是否相同,于是调用 hashCode 返回的结果就是 true,再去调用 equals 方法,发现两个对象确实是相等的,于是就返回 true 了,因此 Set 集合就不会存储两个一模一样的数据了,于是整个程序的执行就正常了。

总结

hashCode 和 equals 两个方法是用来协同判断两个对象是否相等的,采用这种方式的原因是可以提高程序插入和查询的速度,如果在重写 equals 时,不重写 hashCode,就会导致在某些场景下,例如将两个相等的自定义对象存储在 Set 集合时,就会出现程序执行的异常,为了保证程序的正常执行,所以我们就需要在重写 equals 时,也一并重写 hashCode 方法才行。

面试如何回答

1.两个对象的Hashcode值相等,但是两个对象的内容值不一定相等;—Hash冲突的问题
2.两个对象的值Equals比较相等的情况下,则两个对象的Hashcode值一定相等;
Hashmap底层中equals和hash值进行比较是否重复和Set集合
在讲一下阿里java手册
在这里插入图片描述
注意:String 已覆写 hashCode 和 equals 方法,所以我们可以愉快地使用 String 对象作为 key 来使用。

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

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

相关文章

文心ERNIE 3.0 Tiny新升级!端侧压缩部署“小” “快” “灵”!

大家好&#xff0c;今天带来的是有关文心ERNIE 3.0 Tiny新升级内容的文章。 近年来&#xff0c;随着深度学习技术的迅速发展&#xff0c;大规模预训练范式通过一次又一次刷新各种评测基线证明了其卓越的学习与迁移能力。在这个过程中&#xff0c;研究者们发现通过不断地扩大模型…

第七章:Linux最小化搭建环境解说2

配置IP地址&#xff1a;我们先要到网卡配置文件夹里&#xff0c;路径是/etc/sysconfig/network-scripts/&#xff0c;有点长&#xff0c;不过没事&#xff0c;我们要学会习惯&#xff0c;这还是经常用的。然后就是用ls命令查看下面有什么&#xff0c;只有一个文件ifcfg-ens160&…

【位运算问题】Leetcode 136、137、260问题详解及代码实现

Halo&#xff0c;这里是Ppeua。平时主要更新C语言&#xff0c;C&#xff0c;数据结构算法......感兴趣就关注我吧&#xff01;你定不会失望。 &#x1f308;个人主页&#xff1a;主页链接 &#x1f308;算法专栏&#xff1a;专栏链接 我会一直往里填充内容哒&#xff01; &…

sql数据库高级编程总结(一)

1、数学函数&#xff1a;操作一个数据&#xff0c;返回一个结果 &#xff08;1&#xff09;取上限 ceiling 如果有一个小数就取大于它的一个最小整数 列如9.5 就会取到 10 select code,name,ceiling(price) from car &#xff08;2&#xff09;取下限 floor 如果有一个小数就…

Hudi-数据湖

数据湖 数据仓库 数据仓库&#xff08;英语&#xff1a;Data Warehouse&#xff0c;简称数仓、DW&#xff09;,是一个用于存储、分析、报告的数据系统。数据仓库的目的是构建面向分析的集成化数据环境&#xff0c;分析结果为企业提供决策支持&#xff08;Decision Support&am…

Windows 安装Ubuntu18.04虚拟机

在Windows电脑上安装有VMware虚拟机。 Ubuntu下载 下载地址 https://releases.ubuntu.com/?_ga2.112562948.1436579420.1676293914-109238742.1676124458 笔者这边下载的是Ubuntu 18.04版本。 创建虚拟机 打开VMware&#xff0c;文件>新建虚拟机 选择自定义&#xff0…

shellcode,缓冲区溢出漏洞及 远程调call

1.隐藏堆栈调用 在学习shellcode之前, 我们先利用之前已经学习过的知识来构造一个有意思的调用,当然这是建立在学习完毕我们前面的堆栈课程的前提下. 例如我们正常调用过程如下: main---->func2---->func1---->func0 那么,毫无疑问,在堆栈中会出现3个返回到地址,…

云端智创 | 批量化生产,如何利用Timeline快速合成短视频?

本文内容整理自「智能媒体生产」系列课程第三讲&#xff1a;开发者实战&#xff0c;由阿里云智能视频云技术专家分享云剪辑Timeline的功能及使用方法、云剪辑OpenAPI的使用流程、短视频批量生产的基本原理以及使用Timeline合成常见的短视频效果。课程回放见文末。 01 Timeline…

CSDN每日一练:蛇形矩阵

题目名称&#xff1a;蛇形矩阵 时间限制&#xff1a;1000ms内存限制&#xff1a;256M 题目描述 给你一个整数n&#xff0c;输出n∗n的蛇形矩阵。 输入描述&#xff1a; 输入一行&#xff0c;包含一个整数n 输出描述&#xff1a; 输出n行&#xff0c;每行包含n个正整数&#xff…

【重磅】IEEE33配电网两阶段鲁棒优化调度CCG

目录 1 前言 2基本内容 2.1 配网两阶段鲁棒模型 2.2 求解步骤 3部分程序 4程序结果 5程序链接 1 前言 鲁棒优化是电力系统研究的热点&#xff0c;而两阶段鲁棒和分布鲁棒研究就成为各类期刊&#xff08;sci/ei/核心&#xff09;的宠儿&#xff0c;最简单的思路是通过改…

影像组学|案例流程复现

对一篇影像组学的的论文&#xff08;《Development and validation of an MRI-based radiomics nomogram for distinguishing Warthin’s tumour from pleomorphic adenomas of the parotid gland》&#xff09;中方法进行复现。完整地跑通影像组学全流程&#xff0c;对临床影像…

Alibaba微服务组件Nacos配置中心

目录 Nacos配置中心使用 springcloud config 对比 快速开始 搭建nacos-config服务 Config相关配置 配置的优先级 RefreshScope Nacos配置中心使用 官方文档&#xff1a; Nacos config alibaba/spring-cloud-alibaba Wiki GitHub Nacos 提供用于存储配置和其他元数据…

链表基本原理

链表基本原理1.链表1.1 基本原理1.2 链表大O记法表示2. 链表操作2.1 读取2.2 查找2.3 插入2.4 删除3.链表代码实现1.链表 1.1 基本原理 节点 组成链表的数据格子不是连续的。可以分布在内存的各个位置。这种不相邻的格子就叫结点。每个结点保存数据还保存着链表里的下一结点的…

Leetcode—移除元素、删除有序数组中的重复项、合并两个有序数组

移除元素 此题简单&#xff0c;用双指针方法即可&#xff0c; 如果右指针指向的元素不等于val&#xff0c;它一定是输出数组的一个元素&#xff0c;我们就将右指针指向的元素复制到左指针位置&#xff0c;然后将左右指针同时右移&#xff1b; 如果右指针指向的元素等于 val&…

04 OpenCV位平面分解

1 基本概念 位平面分解的核心思想是将图像的每一个像素分解为多个二进制位&#xff0c;分别存储在不同的位平面上。例如&#xff0c;如果一个图像是8位深度的&#xff0c;则可以分解为8个位平面&#xff0c;每个位平面上存储一个二进制位。 位平面分解在图像压缩中有着重要的…

对Node.js 的理解?优缺点?应用场景?

一、是什么 Node.js 是一个开源与跨平台的 JavaScript 运行时环境 在浏览器外运行 V8 JavaScript 引擎&#xff08;Google Chrome 的内核&#xff09;&#xff0c;利用事件驱动、非阻塞和异步输入输出模型等技术提高性能 可以理解为 Node.js 就是一个服务器端的、非阻塞式I/…

中国计算机设计大赛来啦!用飞桨驱动智慧救援机器狗

‍‍中国大学生计算机设计大赛是我国高校面向本科生最早的赛事之一&#xff0c;自2008年开赛至今&#xff0c;一直由教育部高校与计算机相关教指委等或独立或联合主办。大赛的目的是以赛促学、以赛促教、以赛促创&#xff0c;为国家培养德智体美劳全面发展的创新型、复合型、应…

保姆级Vue3+Vite项目实战多布局(下)

写在前面注&#xff1a;本文首发掘金签约专栏&#xff0c;此文为文章同步&#xff01;本文为 Vue3Vite 项目实战系列教程文章第三篇&#xff0c;系列文章建议从头观看效果更佳&#xff0c;大家可关注专栏防走失&#xff01;点个赞再看有助于全文完整阅读&#xff01;此系列文章…

如何在 C++ 应用程序中集成 Spire.XLS for C++

Spire.XLS for C 是一个 Excel 库&#xff0c;供开发人员在任何类型的 C 应用程序中操作 Excel 文档&#xff08;XLS、XLSX、XLSB 和 XLSM&#xff09;。 本文演示了如何以两种不同的方式将 Spire.XLS for C 集成到您的 C 应用程序中。 通过 NuGet 安装Spire.XLS for C通过手动…

一篇文章带你读懂HashMap

HashMap是面试中经常问到的一个知识点,也是判断一个候选人基础是否扎实的标准之一。可见HashMap的掌握是多重要。 一、HashMap源码分析 1、构造函数 让我们先从构造函数说起&#xff0c;HashMap有四个构造方法&#xff0c;别慌 1.1 HashMap() // 1.无参构造方法、// 构造一…