java延迟覆盖_高效Java第九条覆盖equals时总要覆盖hashCode

原标题:高效Java第九条覆盖equals时总要覆盖hashCode

高效Java第九条覆盖equals时总要覆盖hashCode

在每个覆盖了equals方法的类中,也必须覆盖hashCode方法。否则会导致该类无法与基于散列的集合一起正常运作。 hashCode约定

在应用程序的执行期间,只要对象的equals方法所用到的信息没有被修改,那么对着同一个对象调用多次,hashCode方法都必须始终如一地返回同一个整数。

如果两个对象equals(Object)方法比较是相等的,那么调用这两个对象的hashCode方法必须产生同样的整数结果。

如果两个对象equals(Object)比较是不相等的,那么调用这两个对象中的hashCode方法,则不一定要产生不同的整数结果。但是给不相等的对象产生截然不同的整数结果,有可能提高散列表的性能。 没有覆盖hashCode违反第二条约定

因没有覆盖hashCode而违反的关键约定是第二条:相等的对象必须具有相等的散列码。 PhoneNumber例子——没有覆盖hashCode

d5f7721ef4a4dae04e5962e27ec5d4f1.png

553fe5049b1630a970f076bde84fd641.png

该类无法与HashMap一起正常工作:

835a1be36a42e8c949103cb857294aba.png

m.get(new PhoneNumber(408, 867, 5309))返回null。由于PhoneNumber类没有覆盖hashCode方法,从而导致两个相等的实例具有不相等的散列码,违反了hashCode的约定。因此,put方法把电话号码对象存放在一个散列桶中,get方法却在另一个散列桶中查找这个电话号码。即使这两个实例正好被放到同一个散列桶中,get方法也必定会返回null,因为HahsMsap有一项优化,可以将每个项相关联的散列码缓存起来,如果散列码不匹配,也不必检验对象的等同性。

给PhoneNumber类提供一个适当的hashCode方法。下面的hashCode方法是错误的:

8809c0d6964791671788043e006b8488.png

虽然上面的hashCode方法确保了相等的对象总是具有同样的散列码。但是它使得每个对象都具有同样的散列码。因此,每个对象都被映射到同一个散列桶中,使散列表退化为链表。它使得本该线性时间运行的程序变成了以平方级时间在运行。对于规模很大的散列表而言,这关系到散列表能否正常工作。 如何编写好的散列函数

一个好的散列函数倾向于为不相等的对象产生不相等的散列码。散列函数应该把集合中不相等的实例均匀地分布到所有可能的散列值上。

1.把某个非零的常数值,比如17,保存在一个名为result的int类型的变量中。2.对于对象中每个关键域f(指equals方法涉及的每个域),完成以下步骤:a。为该域计算int类型的散列码c:i.如果该域是boolean类型,则计算(f?1:0)。ii.如果该域是byte、char、short或者int类型,则计算(int)f。iii.如果该域是long类型,则计算(int)(f ^ (f >>> 32))。iv.如果该域是float类型,则计算Float.floatToIntBits(f)。v.如果该域是double类型,则计算Double.doubleToLongBits(f),然后按照步骤2.a.iii,为得到的long类型值计算散列值。vi.如果该域是一个对象引用,并且该类的equals方法通过递归地调用equals方法来比较这个域,则同样为这个域递归地调用hashCode。如果需要更复杂的比较,则为这个域计算一个范式,然后针对这个范式调用hashCode。如果这个域的值为null,则返回0(或者其他某个常数,但通常是0)。

vii.如果该域是一个数组,则要把每一个元素当做单独的域来处理。递归地应用上述规则,对每个重要的元素计算一个散列码,然后根据步骤2.b中的做法把这些散列值组合起来。如果数组域中的每个元素都很重要,建议使用Arrays.hashCode方法。b.把步骤2.a中计算得到的散列码c合并到result中:result = 31 * result + c;3.返回result。

4.写完了hashCode方法之后,问问自己“相等的实例是否都具有相等的散列码”。建议编写单元测试。

计算散列码可以把冗余域排除在外。如果一个域的值可以根据参与计算的其他域的值计算出来,则可以把这样的域排除在外。必须排除equals比较计算中没有用到的任何域,否则很有可能违反hashCode约定的第二条。

值17是任选的。步骤2.b中的乘法部分使得散列值依赖于域的顺序,如果一个类中包含多个相似的域,这样的乘法运算就会产生一个更好的散列函数。String的散列函数省略了乘法部分,那么只是字母顺序不同的所有字符串就会有相同的散列码。选择31是因为它是一个奇素数。如果乘数是偶数,并且乘法溢出的话,信息就会丢失,因为与2相乘等价于移位运算。使用素数的好处并不很明显,但习惯上都使用素数来计算散列结果。31可以利用移位和减法来代替乘法,可以得到更好的性能:31 * i == (i << 5) -i。JVM可以自动完成这种优化。 给PhoneNumber编写好的hashCode

PhoneNumber类的hashCode:

3e002f7d777edc563e2081cb4b2bab1f.png 缓存散列码

不可变类如果计算散列码的开销比较大,就应该考虑把散列码缓存在对象内部,而不是每次请求的时候都重新计算散列码。如果类的大多数对象都会被用做散列键,就应该在创建实例的时候计算散列码。否则,可以选择“延迟初始化”散列码,一直到hashCode被第一次调用的时候才初始化。PhoneNumber类的对象有可能会经常被作为散列键:

a04cbc8797da270c997537700b073f46.png

7d35253ed2f5ec1847a8c10eed99b075.png 不要排除对象的关键部分

不要试图从散列码计算中排除掉一个对象的关键部分来提高性能。即使这样得到的散列函数运行起来更快,但是它的效果不见得会好,可能会导致散列表慢到根本无法使用。在实践中,散列函数可能面临大量的实例,在选择忽略的区域之中,这些实例区别非常大。散列函数会把所有这些实例映射到极少数的散列码上,基于散列的集合将会显示出平方级的性能指标。JDK2之前的String散列函数至多只检查16个字符,从第一个字符开始,在整个字符串中均匀选取。对于大型集合,该散列函数表现出了病态行为。 不要规定散列函数的细节

Java平台类库中的许多类,String、Integer、Date等都可以把hashCode方法返回的确切值规定为该实例值的一个函数。但是这并不是一个好注意,这会严格地限制了在将来的版本中改进散列函数的能力。如果没有规定散列函数的细节,那么当你发现了它的内部缺陷时,就可以在后面的发行版本中修正它,确信没有任何客户端会依赖于散列函数返回的确切值。返回搜狐,查看更多

责任编辑:

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

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

相关文章

原生js简单实现双向数据绑定原理

根据对象的访问器属性去监听对象属性的变化&#xff0c;访问器属性不能直接在对象中设置&#xff0c;而必须通过 defineProperty() 方法单独定义。 访问器属性的"值"比较特殊&#xff0c;读取或设置访问器属性的值&#xff0c;实际上是调用其内部特性&#xff1a;get…

java中write方法报错_Java中管道报错:Write end dead

今天看了下关于管道的通信&#xff0c;Java中的管道只能在同一进程的不同线程间通信。今天测试两个线程进行通信发现报错。下面是我测试的代码。package com.wpl.testIO;import java.io.IOException;import java.io.PipedInputStream;import java.io.PipedOutputStream;public …

神盾局特工第四季/全集Agents Of SHIELD迅雷下载

英文全名Agents Of SHIELD&#xff0c;第4季(2016)ABC. 本季看点&#xff1a;《神盾局特工》&#xff08;Agents Of SHIELD&#xff09;第三季季终集里&#xff0c;我们终于知道谁死了……但死的不是一个&#xff0c;而是两个。在这两集中&#xff0c;很多角色都遭遇过险境&…

php科学计数法转string,php如何将科学计数法转数字

php将科学计数法转数字的实现方法&#xff1a;首先通过if语句判断指定的数值是否为科学计数法&#xff1b;然后提取科学计数法中有效的数据&#xff1b;接着正式处理该数据&#xff1b;最后调用“convert_scientific_number_to_normal”方法实现转换即可。PHP将科学计数法转换为…

php8vsgo,服务端 I/O 性能:Node、PHP、Java、Go 的对比

原标题&#xff1a;服务端 I/O 性能&#xff1a;Node、PHP、Java、Go 的对比了解应用程序的输入/输出(I/O)模型意味着理解应用程序处理其数据的载入差异&#xff0c;并揭示其在真实环境中表现。或许你的应用程序很小&#xff0c;在不承受很大的负载时&#xff0c;这并不是个严重…

Python day8

阅读目录 为什么要用函数  函数的定义与调用  函数的返回值  函数的参数  本章小结返回顶部为什么要用函数 现在python届发生了一个大事件&#xff0c;len方法突然不能直接用了。。。 然后现在有一个需求&#xff0c;让你计算hello world的长度&#xff0c;你怎么计算&…

java创建对象过七夕,想 new 个对象过七夕,她却抛了异常

原标题&#xff1a;想 new 个对象过七夕&#xff0c;她却抛了异常关注 “”导读&#xff1a;单身之痛......作者 | 轩辕之风来源 | 编程技术宇宙(ID&#xff1a;xuanyuancoding)七夕又到了&#xff0c;单身汪们太难了&#xff0c;每年不仅要经历双十一&#xff0c;要经历2.14&a…

【Redis】解析Redis和Java传递数据

在Java中使用Redis之前需要导入 jedis.jar 包&#xff0c;由于Redis是基于key-value进行数据存储&#xff0c;java中的数据存储到Redis中有许多方式&#xff0c;这里笔者介绍采用JSON字符串和对象序列化两种方式。 1&#xff0c;使用JSON方式 首先将Java对象转化为JSON字符串 …

C#带按钮的文本框TextBoxContainButton

经常需要用到各种组合控件&#xff0c;每次组合太麻烦&#xff0c;通过打包成自定义控件&#xff0c;方便调用。 带按钮的文本框&#xff0c;如下图&#xff1a; 文本框内可以输入文本&#xff0c;响应文本框内容变化事件&#xff0c;按钮可以设置点击事件&#xff0c;图标 通过…

Windows单机配置Zookeeper环境

转自&#xff1a;http://www.jianshu.com/p/f7037105db46 首先要确保机器已经安装好java环境&#xff0c;并且配置好环境变量 http://apache.fayea.com/zookeeper/current/ 下载后&#xff0c;解压缩到硬盘&#xff0c;我这里解压到了 D:\WorkSoftware\zookeeper_3.4.9 解压缩在…

三层架构—简析

三层学习完了&#xff0c;第一次验收的时候&#xff0c;自己理解的也不是非常到位&#xff0c;后来又又一次敲了一遍登陆样例&#xff0c;查阅了一些资料 进行第二次验收才感觉清晰了很多。之前画时序图时我就想过时序图基本上也是非常好的体现了三层&#xff0c;当时也和别人讨…

机房收费系统之结账

其实&#xff0c;我认为机房收费系统中结账的部分是耗我精力最多的。首先我就不明确结账是干嘛的&#xff0c;所以一上来就晕乎乎。后来看了一篇博客说结账方便老板管理的才明确了为什么是“操作员”。这里面要理清的一点&#xff0c;结账的内容是未结账的。 暂时汇总的信息&am…

Java线上应用故障排查之一:高CPU占用

一个应用占用CPU很高&#xff0c;除了确实是计算密集型应用之外&#xff0c;通常原因都是出现了死循环。 以我们最近出现的一个实际故障为例&#xff0c;介绍怎么定位和解决这类问题。 根据top命令&#xff0c;发现PID为28555的Java进程占用CPU高达200%&#xff0c;出现故障。 …

Java并发编程实战 代码bug,Java并发编程实战(1)- 并发程序的bug源头

概述并发编程一般属于编程进阶部分的知识&#xff0c;它会涉及到很多底层知识&#xff0c;包括操作系统。编写正确的并发程序是一件很困难的事情&#xff0c;由并发导致的bug&#xff0c;有时很难排查或者重现&#xff0c;这需要我们理解并发的本质&#xff0c;深入分析Bug的源…

ajax小结

转载于:https://www.cnblogs.com/infernoyy/p/7250548.html

app推送以及提示音java,springboot 整合 Jpush 极光推送

产品简介&#xff1a;JPush 是经过考验的大规模 App 推送平台&#xff0c;每天推送消息数超过 5 亿条。 开发者集成 SDK 后&#xff0c;可以通过调用 API 推送消息。同时&#xff0c;JPush 提供可视化的 web 端控制台发送通知&#xff0c;统计分析推送效果。 JPush 全面支持 An…

Lydsy2017年4月月赛 抵制克苏恩

Description小Q同学现在沉迷炉石传说不能自拔。他发现一张名为克苏恩的牌很不公平。如果你不玩炉石传说&#xff0c;不必担心&#xff0c;小Q同学会告诉你所有相关的细节。炉石传说是这样的一个游戏&#xff0c;每个玩家拥有一个30 点血量的英雄&#xff0c;并且可以用牌召唤至…

怎样学习(3):迭代学习,精益求精

古人云「十年寒窗无人问。一举成名天下知」&#xff0c;这是中国古代为数不多的读书人的真实写照。大多数读书人仅仅有十年寒窗&#xff0c;却不见得成名。 在软件开发领域有瀑布模式的软件project方法论。它将软开发的几个过程「需求分析&#xff0c;概要设计&#xff0c;具体…

matlab宏参赛,MATLAB杯无人机大赛 | 决赛通知!

原标题&#xff1a;MATLAB杯无人机大赛 | 决赛通知&#xff01;重磅消息——决赛通知&#xff01;经过近5个多月的准备&#xff0c;MATLAB杯无人机比赛即将迎来精彩的决赛&#xff0c;来自全国10强的参赛队伍&#xff0c;齐聚羊城广州&#xff0c;美丽的中山大学&#xff0c;进…

php表格js特效,JavaScript表格隔行变色和Tab标签页特效示例【附jQuery版】

本文实例讲述了JavaScript表格隔行变色和Tab标签页特效。分享给大家供大家参考&#xff0c;具体如下&#xff1a;最近一直在看JavaScript知识&#xff0c;偶尔也穿插一点Jquery&#xff0c;感觉Jquery用起来真爽&#xff0c;减少了很多的代码量&#xff0c;而且学习也不是很高。…