说⼀说hashCode()和equals()的关系

1.是什么

    hashCode()equals() 是 Java 中两个非常重要的基础方法,主要用于对象的比较和哈希相关操作。它们的关系在于:如果两个对象根据 equals() 方法相等,那么它们的 hashCode() 必须相同,但反过来并不一定成立。理解它们的关系非常关键,特别是在使用哈希表数据结构(如 HashMapHashSet)时。


1. equals() 方法

    equals() 方法用于比较两个对象是否相等。默认情况下,它比较的是对象的引用(即内存地址),但通常我们会根据对象的实际内容来重写这个方法。例如,在 Person 类中,我们可能会根据 name 和 age 属性来判断两个 Person 对象是否相等。


2. hashCode() 方法

    hashCode() 方法返回对象的哈希码值,这是一个整数。哈希码用于确定对象在哈希表中的索引位置。理想情况下,不同的对象应该产生不同的哈希码,但这并不是强制的。重要的是,如果两个对象通过 equals() 方法比较是相等的,那么它们的 hashCode() 方法必须返回相同的整数值。


3.hashCode()equals()的关系

  1. 等价性(Equality)

    • 如果两个对象根据equals()方法是相等的,那么这两个对象必须具有相同的哈希码。即o1.equals(o2)true时,o1.hashCode()必须与o2.hashCode()返回相同的整数值。
    • 这是因为基于哈希的集合(如HashMap)使用hashCode()来快速定位对象所在的桶(bucket),然后使用equals()来检查对象是否真的相等。
  2. 不一致性(Inconsistency)

    • 如果两个对象的hashCode()返回相同的值,这并不意味着这两个对象必须相等。不同的对象可能有相同的哈希码,这就是所谓的哈希冲突。
    • 但是,如果两个对象的hashCode()返回不同的值,那么这两个对象一定不相等。

总结:

  • 如果两个对象相等(即 equals() 返回 true),则它们的 hashCode() 值必须相等。否则,基于哈希的集合(如 HashMapHashSet)在存储和查找对象时会发生错误。
  • 如果两个对象的 hashCode() 值相等,它们不一定相等(即 equals() 不一定返回 true)。但这样会导致哈希表中不同对象落入同一个“桶”,从而可能影响查找性能。

4.为什么要重写 hashCode()equals()

        equals() ⽅法⽤于⽐较两个对象的内容是否相等。在Java中,默认实现是⽐较对象的引⽤,即⽐较两个对象是否指向内存中的相同位置。但通常,我们希望⽐较对象的内容是否相等。鉴于这种情况,Object类中 equals() ⽅法的默认实现是没有实⽤价值的,所以通常都要重写。⽽由于hashCode()与equals()具有联动关系(如果两个对象相等,则它们必须有相同的哈希码),所以equals()⽅法重写时,通常也要将hashCode()进⾏重写,使得这两个⽅法始终保持⼀致性。


代码示意:

不重写 hashCode()equals() 方法

        默认情况下,equals()hashCode() 是基于对象的内存地址比较的:

class Person {
    String name;
    int age;

    Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
}

public class Main {
    public static void main(String[] args) {
        Person p1 = new Person("John", 25);
        Person p2 = new Person("John", 25);

        System.out.println(p1.equals(p2)); // 输出:false,默认比较的是内存地址
        System.out.println(p1.hashCode() == p2.hashCode()); // 输出:false,hashCode 基于内存地址
    }
}
重写 equals() 但不重写 hashCode()

        如果你只重写了 equals() 而没有重写 hashCode(),则会出现问题:即使两个对象根据 equals() 相等,它们的 hashCode() 可能不同。这会导致哈希表无法正确处理它们。

class Person {
    String name;
    int age;

    Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) return true;
        if (obj == null || getClass() != obj.getClass()) return false;
        Person person = (Person) obj;
        return age == person.age && name.equals(person.name);
    }
}

public class Main {
    public static void main(String[] args) {
        Person p1 = new Person("John", 25);
        Person p2 = new Person("John", 25);

        System.out.println(p1.equals(p2)); // 输出:true,内容相同
        System.out.println(p1.hashCode() == p2.hashCode()); // 输出:false,hashCode 不相等
        
        // 放入 HashSet 中
        HashSet<Person> set = new HashSet<>();
        set.add(p1);
        set.add(p2);
        System.out.println(set.size()); // 输出:2,应该是1(因为 equals 相等),但 hashCode 不同导致重复
    }
}
重写 equals()hashCode()

        如果我们重写了 equals() 方法,还必须重写 hashCode() 方法来保证相等的对象有相同的哈希值。这样,哈希表会正确处理这些对象。

class Person {
    String name;
    int age;

    Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) return true;
        if (obj == null || getClass() != obj.getClass()) return false;
        Person person = (Person) obj;
        return age == person.age && name.equals(person.name);
    }

    @Override
    public int hashCode() {
        return name.hashCode() + age; // 基于对象的属性计算 hashCode
    }
}

public class Main {
    public static void main(String[] args) {
        Person p1 = new Person("John", 25);
        Person p2 = new Person("John", 25);

        System.out.println(p1.equals(p2)); // 输出:true
        System.out.println(p1.hashCode() == p2.hashCode()); // 输出:true

        // 放入 HashSet 中
        HashSet<Person> set = new HashSet<>();
        set.add(p1);
        set.add(p2);
        System.out.println(set.size()); // 输出:1,说明 p1 和 p2 被认为是相同的对象
    }
}

5. 总结

  • equals() 用于比较两个对象是否相等,通常基于对象的内容来比较。
  • hashCode() 用于生成对象的哈希值,主要用于提高基于哈希表数据结构的效率。
  • 如果重写了 equals(),务必也要重写 hashCode(),以确保相等的对象拥有相同的哈希值,从而保证哈希表中的正常操作。
  • 如果两个对象 equals() 返回 true,它们的 hashCode() 必须相同;但 hashCode() 相同的对象不一定 equals() 返回 true

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

机器学习特征构建与特征筛选

前言 上一篇文章讲述了原始特征分析和处理&#xff0c;保障后续拿到的是干净的特征变量&#xff0c;但实际这些特征对于建模不一定是有效的&#xff0c;所以需要在原始特征的基础上&#xff0c;结合业务场景做特征变量的衍生&#xff0c;提升数据的表达能力。此外&#xff0c;…

【C++】unordered系列

前言&#xff1a; 在C11及以后的标准中&#xff0c;unordered容器是标准模板库&#xff08;STL&#xff09;的一部分&#xff0c;提供了高效的数据结构选项&#xff0c;适用于需要快速查找和插入操作的场景。 unordered通常与关联容器一起使用&#xff0c;特别是unordered_map和…

图论篇--代码随想录算法训练营第六十一天打卡| Floyd 算法,A*算法

Floyd 算法&#xff08;求多源汇最短路&#xff09; 题目链接&#xff1a;97. 小明逛公园 题目描述&#xff1a; 小明喜欢去公园散步&#xff0c;公园内布置了许多的景点&#xff0c;相互之间通过小路连接&#xff0c;小明希望在观看景点的同时&#xff0c;能够节省体力&…

句子成分——每日一划(八)

目录 一、原句 二、第一部分 三、第二部分 一、原句 In class society everyone lives as a member of a particular class, and every kind of thinking, without exception, is stamped with the brand of a class. 来源&#xff1a;二、阶级和阶级斗争 二、第一部分 In…

谷粒商城のElasticsearch

文章目录 前言一、前置知识1、Elasticsearch 的结构2、倒排索引 (Inverted Index)2.1、 索引阶段2.2、查询阶段 二、环境准备1、安装Es2、安装Kibana3、安装 ik 分词器 三、项目整合1、引入依赖2、整合业务2.1、创建索引、文档、构建查询语句2.2、整合业务代码 后记 前言 本篇介…

初识php库管理工具composer的体验【爽】使用phpword模板功能替换里面的字符串文本

需求&#xff1a; 做了一个租赁的项目&#xff0c;里面要求签署个人授权协议&#xff0c;里面要填写姓名&#xff0c;手机号&#xff0c;身份证号&#xff0c;签署日期等参数&#xff0c;格式如下图 格式&#xff1a; 如上图&#xff0c;word中的字符串模板变量使用${varname…

Java设计模式—面向对象设计原则(三) -----> 依赖倒转原则DIP(完整详解,附有代码+案例)

文章目录 3.3 依赖倒转原则(DIP)3.3.1概述3.3.2 案例 3.3 依赖倒转原则(DIP) 依赖倒转原则&#xff1a;Dependency Inversion Principle&#xff0c;DIP 3.3.1概述 高层模块不应该依赖低层模块&#xff0c;两者都应该依赖其抽象&#xff1b;抽象不应该依赖细节&#xff0c;细…

演示:基于WPF的自绘的中国地铁轨道控件

一、目的&#xff1a;演示一个基于WPF的自绘的中国地铁轨道控件 二、效果演示 北京地铁 成都地铁 上海地铁 深圳地铁 南京地铁 长春地铁 哈尔滨地铁 武汉地铁 厦门地铁 香港地铁 三、功能 支持平移、缩放等操作 鼠标悬停显示线路信息和站点信息 按表格显示&#xff0c;按纸张…

MySQL —— 索引

索引的概念 MySQL的索引是⼀种数据结构&#xff0c;它可以帮助数据库高效地查询、更新数据表中的数据。索引通过 ⼀定的规则排列数据表中的记录&#xff0c;使得对表的查询可以通过对索引的搜索来加快速度。 MySQL索引类似于书籍的目录&#xff0c;通过指向数据行的位置&…

PCIe进阶之TL:First/Last DW Byte Enables Rules Traffic Class Field

1 First/Last DW Byte Enables Rules & Attributes Field 1.1 First/Last DW Byte Enables Rules Byte Enable 包含在 Memory、I/O 和 Configuration Request 中。本文定义了相应的规则。Byte Enable 位于 header 的 byte 7 。对于 TH 字段值为 1 的 Memory Read Request…

Requests-HTML模块怎样安装和使用?

要安装和使用Requests-HTML模块&#xff0c;您可以按照以下步骤进行操作&#xff1a; 打开命令行界面&#xff08;如Windows的命令提示符或Mac的终端&#xff09;。 使用pip命令安装Requests-HTML模块。在命令行中输入以下命令并按回车键执行&#xff1a; pip install request…

前端网页代码编辑器 Monaco Editor

前端网页代码编辑器 Monaco Editor Monaco Editor Monaco Editor 是由 Microsoft 开发的一款基于 Web 技术的开源代码编辑器&#xff0c;它是 Visual Studio Code 编辑器的核心。Monaco Editor 可以嵌入到网页中&#xff0c;提供类似于 Visual Studio Code 的编辑体验。 官方…

数据结构 Java DS——分享部分链表题目 (2)

目录 前言 题目一 —— 链表的回文结构 题目二 —— 二进制链表转整数 题目三 —— 设计链表 结尾 前言 关于JAVA的链表,笔者已经写了两篇博客来介绍了,今天给笔者们带来第三篇,也是分享了一些笔者写过的,觉得挺好的题目,链接也已经挂上了,笔者们可以去看看…

redis 基本数据类型—string类型

一、介绍 Redis 中的字符串&#xff0c;直接就是按照二进制数据的方式存储的&#xff0c;不会做任何的编码转换。 Redis对于 string 类型&#xff0c;限制了大小最大是512M 二、命令 SET 将 string 类型的 value 设置到 key 中。如果 key 之前存在&#xff0c;则覆盖&#…

亚马逊、沃尔玛、敦煌网、Target塔吉特、Temu环境搭建测评技术!

海外跨境电商各大主要平台正不断力推半托管模式&#xff0c;不断对商家开出众多吸引和扶持政策。全托管是指电商平台全面负责店铺的运营&#xff0c;包括仓储、配送、售后等&#xff0c;而商家主要负责提供货品。半托管模式则基本由商家自主经营&#xff0c;平台只负责仓配物流…

java中Class文件的文件格式

无关性的基石 计算机底层只能识别二进制&#xff0c;由CPU直接处理二进制&#xff0c;在底层上面是操作系统&#xff0c;在操作系统上面就是虚拟机&#xff0c;java有一个口号&#xff0c;“一次编写&#xff0c;到处运行”这个不太可能在操作系统层面上实现&#xff0c;不同的…

俄罗斯方块——C语言实践(Dev-Cpp)

目录 1、创建项目(尽量不使用中文路径) 2、项目复制 3、项目配置 ​1、调整编译器 2、在配置窗口选择参数标签 3、添加头文件路径和库文件路径 4、代码实现 4.1、main.c 4.2、draw.h 4.3、draw.c 4.4、shape.h 4.5、shape.c 4.6、board.h 4.7、board.c 4.8、cont…

Vue.js入门系列(二十九):深入理解编程式路由导航、路由组件缓存与路由守卫

个人名片 &#x1f393;作者简介&#xff1a;java领域优质创作者 &#x1f310;个人主页&#xff1a;码农阿豪 &#x1f4de;工作室&#xff1a;新空间代码工作室&#xff08;提供各种软件服务&#xff09; &#x1f48c;个人邮箱&#xff1a;[2435024119qq.com] &#x1f4f1…

解锁编程潜力,从掌握GitHub开始

目录&#xff1a; 一、搜索开源项目 1、什么是Git 2、Github常用词含义 3、一个完整的项目界面 4、使用Github搜索项目 1&#xff09;in关键词 2&#xff09;star或fork数量去查找 3&#xff09;awesome加强搜索 二、访问速度慢的解决 1、使用网易UU加速器 2、使用…

Visual Studio(vs)下载安装C/C++运行环境配置和基本使用注意事项

基本安装 点击跳转到vs官网点击箭头所指的按钮进行下载双击运行刚才下载好的下载器点击继续勾选“使用C的桌面开发”和“Visual Studio扩展开发”点击“安装位置”&#xff0c;对vs的安装位置进行更改。你可以跟我一样只选择D盘或者其他你空闲的盘&#xff0c;然后将默认的路径…