Java的hashCode方法和equals方法

Java的hashCode方法和equals方法

简述

public native int hashCode()public boolean equals(Object obj) {return (this == obj);
}

特性说明

  • 返回对象的哈希值。
  • 支持此方法是为了使用哈希表,例如java.util.HashMap提供的哈希表。

hashCode的通用约定如下:

  • 在 Java 应用程序的一次执行过程中,如果对象的equals比较方法中的信息未被修改,只要对同一对象多次调用 hashCode 方法,该方法就必须始终如一地返回相同的整数。该整数不必在应用程序的一次执行与另一次执行之间保持一致。
  • 如果根据 equals(Object)方法判断两个对象相等,那么在两个对象上分别调用 hashCode 方法必须产生相同的整数结果。
  • 根据equals(Object)方法,如果两个对象不相等,则不要求对这两个对象中的每一个调用hashCode方法必须产生不同的整数结果。然而,程序员应该意识到,为不相等的对象生成不同的整数结果可以提高哈希表的性能。

在合理可行的范围内,类 Object 定义的hashCode方法会为不同的对象返回不同的整数。(这通常是通过将对象的内部地址转换为整数来实现的,但 Java™ 编程语言并不要求这种实现技术)。

特性说明

判断两个对象指向的内存空间的值是否相等,简单说就是比较的是两个对象的内容是否相等

equals 方法实现了非空对象引用的等价关系:

  • 具有自反性:对于任何非空引用值 x,x.equals(x) 都应返回 true
  • 具有对称性:对于任何非空引用值 x 和 y,当且仅当 y.equals(x)返回 true 时,x.equals(y) 应返回 true
  • 具有传递性:对于任何非空引用值 x、y 和 z,如果x.equals(y)返回 true 且 y.equals(z) 返回 true,则 x.equals(z)应返回 true
  • 具有一致性:对于任何非空引用值 x 和 y,在对象的等价比较中使用的信息没有被修改的情况下,多次调用 x.equals(y) 都会一致地返回 true 或一致地返回 false
  • 具有非空性:对于任何非空引用值 x,x.equals(null) 都应返回 false

Object类的 equals 方法实现了对象上最有辨别力的等价关系;也就是说,对于任何非空引用值 x 和 y,只有当 x 和 y 指向同一个对象时,该方法才返回 true(x == y 的值为 true)。

需要注意的是,一般来说,只要重载了 hashCode 方法,就必须重载该方法,以保持 hashCode 方法的一般规则,即相等的对象必须具有相等的散列代码。

== 比较的是变量(栈)内存中存放的对象的(堆)内存地址,用来判断两个对象的地址是否相同,即是否是指相同一个对象。

(1)若比较的是基础数据类型,则比较的是他们的值是否相等,比如两个int类型的变量,比较的是变量的值是否一样。

(2)若比较的是引用数据类型,则较的是引用的地址是否相同,比如说新建了两个User对象,比较的是两个User的地址是否一样。

String中有一种特殊场景,String s="a";不同于New对象,它是一个直接量,在常量池中新建"a"。这种形式的字符串,在JVM内部发生字符串拘留,即当声明这样的一个字符串后,JVM会在常量池中先查找有有没有一个值为"a"的对象。如果有,就会把它赋给当前引用.即原来那个引用和现在这个引用指点向了同一对象;如果没有,则在常量池中新创建一个"b",下一次如果有String s1=“b”;又会将s1指向“b”这个对象,即以这形式声明的字符串,只要值相等,任何多个引用都指向同一对象。

package com.donny.demo;/*** @author 1792998761@qq.com* @description* @date 2023/8/28*/
public class Test {public static void main(String[] args) {Integer a1 = 1;Integer a2 = 1;String b1 = new String("111");String b2 = new String("111");String s1 = "222";String s2 = "222";UserName u1 = new UserName("张三");UserName u2 = new UserName("张三");System.out.println(a1 == a2);System.out.println(a1.equals(a2));System.out.println(b1 == b2);System.out.println(b1.equals(b2));System.out.println(s1 == s2);System.out.println(s1.equals(s2));System.out.println(u1 == u2);System.out.println(u1.equals(u2));}public static class UserName {private String name;public UserName(String name) {this.name = name;}public String getName() {return name;}public void setName(String name) {this.name = name;}}
}

执行结果

true
true
false
true
true
true
false
false

什么时候需要重写hashCode方法

  1. 只要重写了equals 方法就要重写hashCode方法
  2. 因为 Set 存储的是不重复的对象,依据 hashCode 和 equals 进行判断,所以 Set 存储的对象必须覆写这两种方法 。
  3. 如果自定义对象作为 Map 的键,那么必须覆写 hashCode方法 和 equals。

如何重写

简单做法 来自Effective Java

  1. 声明一个int的变量result,用一个非零的常量值,作为第一个关键域的散列值,比如17

  2. 对于对象中每个关键域f(equals方法中涉及的每个域),完成以下步骤:

    1. 为该域计算int类型的散列码c:

      1. 如果该域是boolean类型,则计算(f?1:0)。
      2. 如果该域是bytecharshort或者int类型,则计算(int)f
      3. 如果该域是long类型,则计算(int)(f^(f>>>32))
      4. 如果该域是float类型,则计算Float.floatToIntBits(f)
      5. 如果该域是double类型,则计算Double.doubleToLongBits(f),然后按照步骤2.1.3,为得到的long类型值计算散列值。
      6. 如果该域是一个对象引用,并且该类的equals方法通过递归地调用equals的方式来比较这个域,则同样为这个域递归地调用hashCode。如果需要更复杂的比较,则为这个域计算一个范式(canonical representation),然后针对这个范式调用hashCode。如果这个域的值为null,则返回0(其他常数也行)。
      7. 如果该域是一个数组,则要把每一个元素当做单独的域来处理。也就是说,递归地应用上述规则,对每个重要的元素计算一个散列码,然后根据步骤2.2中的做法把这些散列值组合起来。如果数组域中的每个元素都很重要,可以利用发行版本1.5中增加的其中一个Arrays.hashCode方法。
    2. 按照下面的公式,把步骤2.1中计算得到的散列码c合并到result中:result = 31 * result + c; //此处31是个奇素数,并且有个很好的特性,即用移位和减法来代替乘法,可以得到更好的性能:31*i == (i<<5) - i, 现代JVM能自动完成此优化。

  3. 返回result

  4. 检验并测试该hashCode实现是否符合通用约定。

对hash冲突要求高的,可以参考谷歌Guava的Hashing类。

JDK String的重写例子

    public int hashCode() {int h = hash;if (h == 0 && value.length > 0) {char val[] = value;for (int i = 0; i < value.length; i++) {h = 31 * h + val[i];}hash = h;}return h;}public boolean equals(Object anObject) {if (this == anObject) {return true;}if (anObject instanceof String) {String anotherString = (String)anObject;int n = value.length;if (n == anotherString.value.length) {char v1[] = value;char v2[] = anotherString.value;int i = 0;while (n-- != 0) {if (v1[i] != v2[i])return false;i++;}return true;}}return false;}

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

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

相关文章

Spring Boot(Vue3+ElementPlus+Axios+MyBatisPlus+Spring Boot 前后端分离)【三】

&#x1f600;前言 本篇博文是关于Spring Boot(Vue3ElementPlusAxiosMyBatisPlusSpring Boot 前后端分离)【三】的分享&#xff0c;希望你能够喜欢 &#x1f3e0;个人主页&#xff1a;晨犀主页 &#x1f9d1;个人简介&#xff1a;大家好&#xff0c;我是晨犀&#xff0c;希望我…

keepalived+lvs(DR)

目录 一、作用 二、安装 1、在192.168.115.3 和192.168.115.4 上安装ipvs和keepalived&#xff1a; 2、配置keepalived 3、查看lvs节点状态 4、web节点配置 5、在web节点上调整ARP参数 6、配置虚拟IP地址与添加回环路由 7、配置nginx网页文档 8、启动服务 9、测试 一…

上位机采集8通道模拟量模块数据

模拟量模块和上位机的配合使用可以实现对模拟量数据的采集、传输和处理。下面是它们配合使用的一般步骤&#xff1a;1. 连接模拟量模块&#xff1a;将模拟量模块与上位机进行连接。这通常涉及将模拟量模块的输入通道与被监测的模拟信号源连接起来&#xff0c;如传感器、变送器等…

14. Docker中实现CI和CD

目录 1、前言 2、什么是CI/CD 3、部署Jenkins 3.1、下载Jenkins 3.2、启动Jenkins 3.3、访问Jenkins页面 4、Jenkins部署一个应用 5、Jenkins实现Docker应用的持续集成和部署 5.1、创建Dockerfile 5.2、集成Jenkins和Docker 6、小结 1、前言 持续集成(CI/CD)是一种…

18-使用钩子函数判断用户登录权限-登录前缀

钩子函数的两种应用: (1). 应用在app上 before_first_request before_request after_request teardown_request (2). 应用在蓝图上 before_app_first_request #只会在第一次请求执行,往后就不执行, (待定,此属性没调试通过) before_app_request # 每次请求都会执行一次(重点…

【Three.js + Vue 构建三维地球-Part One】

Three.js Vue 构建三维地球-Part One Vue 初始化部分Vue-cli 安装初始化 Vue 项目调整目录结构 Three.js 简介Three.js 安装与开始使用 实习的第一个任务是完成一个三维地球的首屏搭建&#xff0c;看了很多的案例&#xff0c;也尝试了用 Echarts 3D地球的模型进行构建&#xf…

设计模式中的关系

文章目录 一、依赖概念 二&#xff0c;关联概念 三、聚合概念 四、组合概念 五、实现概念 六、继承概念 图总结整体总结 一、依赖 概念 依赖是一种临时使用关系&#xff0c;代码层体现为作为参数。 具体体现&#xff1a;依赖者调用被依赖者的局部变量、参数、静态方法&#…

docker项目实战

目录 1、使用mysql:5.6和 owncloud 镜像&#xff0c;构建一个个人网盘。 1&#xff09;拉取mysql:5.6和owncloud镜像 2&#xff09;后台运行容器 3&#xff09;通过ip:端口的方式访问owncloud 2、安装搭建私有仓库 Harbor 1&#xff09;首先准备所需包 2&#xff09;安装h…

Lua与C++交互(一)————堆栈

Lua与C交互&#xff08;一&#xff09;————堆栈 Lua虚拟机 什么是Lua虚拟机 Lua本身是用C语言实现的&#xff0c;它是跨平台语言&#xff0c;得益于它本身的Lua虚拟机。 虚拟机相对于物理机&#xff0c;借助于操作系统对物理机器&#xff08;CPU等硬件&#xff09;的一…

HTML番外篇(四)-HTML5新增元素-CSS常见函数-理解浏览器前缀-BFC

一、HTML5新增元素 1.HTML5语义化元素 在HMTL5之前&#xff0c;我们的网站分布层级通常包括哪些部分呢&#xff1f; header、nav、main、footer ◼ 但是这样做有一个弊端&#xff1a; 我们往往过多的使用div, 通过id或class来区分元素&#xff1b;对于浏览器来说这些元素不…

雅思作文复习

目录 我使用的词汇&#xff1a; 上升&#xff1a; 下降&#xff1a; 波动&#xff1a; 保持&#xff1a; 幅度 大变化&#xff1a; 小变化&#xff1a; 雅思评价标准改变 小作文一般花费20分钟&#xff0c;我觉得自己能在18分钟解决是最好 考生在雅思考试中的小作文&a…

嵌入式系统存储体系

一、存储系统概述 主要分为三种&#xff1a;高速缓存&#xff08;cache&#xff09;、主存和外存。 二、高速缓存Cache 高速缓冲存储器中存放的是当前使用得最多得程序代码和数据&#xff0c;即主存中部分内容的副本&#xff0c;其本身无自己的地址空间。在嵌入式系统中Cac…

配置DataX

配置DataX_3.0.0 1.配置DataX2.DataX案例 1.配置DataX 1&#xff09;下载DataX安装包并上传到hadoop102的/opt/software 下载地址&#xff1a;http://datax-opensource.oss-cn-hangzhou.aliyuncs.com/datax.tar.gz .tar.gz到/opt/module [atguiguhadoop102 software]$ tar -zx…

别在说自己不知道docker了,全文通俗易懂的给你说明白docker的基础与底层原理

docker介绍 Docker 是一个开源的应用容器引擎&#xff0c;基于Go语言进行开发实现并遵从Apache2.0 协议开源&#xff0c;基于 Linux 内核的 cgroup&#xff0c;namespace&#xff0c;以及 OverlayFS 类的 Union FS 等技术&#xff0c;对进程进行封装隔离&#xff0c;属于 操作…

Redis.conf详解

Redis.conf详解 配置文件unit单位对大小写不敏感 包含 网络 bind 127.0.0.1 # 绑定的ip protected-mode yes # 保护模式 port 6379 # 端口设置通用 GENERAL daemonize yes # 以守护进程的方式运行 默认为no pidfile /var/run/redis_6379.pid #如果以后台的方式运行&#xff…

python+django+mysql旅游景点推荐系统-前后端分离(源码+文档)

系统主要采用Python开发技术和MySQL数据库开发技术以及基于OpenCV的图像识别。系统主要包括系统首页、个人中心、用户管理、景点信息管理、景点类型管理、景点门票管理、在线反馈、系统管理等功能&#xff0c;从而实现智能化的旅游景点推荐方式&#xff0c;提高旅游景点推荐的效…

javaee idea创建maven项目,使用el和jstl

如果使用el表达式出现下图问题 解决办法 这是因为maven创建项目时&#xff0c;web.xml头部声明默认是2.3&#xff0c;这个默认jsp关闭el表达式 办法1 在每个需要用到el和jstl的页面的上面加一句: <% page isELIgnored"false" %> 方法2 修改web.xml文件开…

睿思BI旗舰版V5.3正式发布

发布时间&#xff1a;2023-7-20 主要更新内容: 1.增加3D地图功能 2.增加水球图 3.增加扇形图&#xff0c;在数据大屏 - 自定义组件中定义。 4.增加指标引导线功能&#xff0c;在数据大屏 - 自定义组件中定义。 5.详情页增加回调函数功能。 6.大屏/仪表盘模版下载&#xff0c;…

【C++】C++ 引用详解 ⑨ ( 常量引用初始化 | C / C++ 常量分配内存的四种情况 )

文章目录 一、常量引用初始化1、使用 " 普通变量 " 初始化 " 常量引用 "2、使用 " 常量 / 字面量 " 初始化 " 常量引用 "3、C / C 常量分配内存的四种情况4、代码示例 - 常量引用初始化 一、常量引用初始化 1、使用 " 普通变量 &…

<八> objectARX开发:动态拖动Jig创建自定义实体

1、介绍 接上一篇文章,在某些情况下,CAD中的实体对象初始参数并不是固定的,我们需要通过jig动态拖动方式来绘制自定义实体,下面就用一个简单的例子来介绍一下自定义实体动态绘制。   实体形状:包括实体夹点和文字夹点拖动实现。 2、效果 3、源码 static void RYMyGrou…