文档章节

java中为什么要重写hashCode和equals?

o
 osc_fmg49rzg
发布于 2019/03/20 09:44
字数 1689
阅读 5
收藏 0

精选30+云产品,助力企业轻松上云!>>>

Java集合中有两个类:List,Set

List是有序可以重复,Set是无序不可以重复

这样添加元素时就要判断元素是否重复

此时就要用到object.equals()方法

但如果集合中元素太多,效率就会很低

所以就发明了hashCode()方法

将集合分成若干个区域,计算每个元素的hash值,根据hash值放入区域中

这样一来,添加元素就要先计算元素的hash值,找到对应区域

如果对应区域为空,就存入

如果对应区域有值,就调用equals方法比较,相同则不存入,不同则散列到其他地址

 

 

这是两个方法的源码,我们可以看出:

  hashcode是本地方法,java的内存是安全的,因此无法根据散列码得到对象的内存地址,但实际上,hashcode是根据对象的内存地址经哈希算法得来的
  而equals方法是严格判断一个对象是否相等的方法(object1 == object2),比较的是两个对象的内存地址
  在我们的业务系统中判断对象时有时候需要的不是一种严格意义上的相等,而是一种业务上(内容)的对象相等。在这种情况下,原生的equals方法就不能满足我们的需求了,所以这个时候我们需要重写equals方法,来满足我们的业务系统上的需求。
  那么为什么在重写equals方法的时候需要重写hashCode方法呢?
  我们先来看一下Object.hashCode的通用约定(摘自《Effective Java》第45页)
  1.在一个应用程序执行期间,如果一个对象的equals方法做比较所用到的信息没有被修改的话,那么,对该对象调用hashCode方法多次,它必须始终如一地返回同一个整数。在同一个应用程序的多次执行过程中,这个整数可以不同,即这个应用程序这次执行返回的整数与下一次执行返回的整数可以不一致。
  2.如果两个对象根据equals(Object)方法是相等的,那么调用这两个对象中任一个对象的hashCode方法必须产生同样的整数结果。
  3.如果两个对象根据equals(Object)方法是不相等的,那么调用这两个对象中任一个对象的hashCode方法,不要求必须产生不同的整数结果。然而,程序员应该意识到这样的事实,对于不相等的对象产生截然不同的整数结果,有可能提高散列表(hash table)的性能。

  如果只重写了equals方法而没有重写hashCode方法的话,则会违反约定的第二条:相等的对象必须具有相等的散列码(hashCode)

  同时对于HashSet和HashMap这些基于散列值(hash)实现的类。HashMap的底层处理机制是以数组的方法保存放入的数据的(Node<K,V>[] table),其中的关键是数组下标的处理。数组的下标是根据传入的元素hashCode方法的返回值再和特定的值异或决定的。如果该数组位置上已经有放入的值了,且传入的键值相等则不处理,若不相等则覆盖原来的值,如果数组位置没有条目,则插入,并加入到相应的链表中。检查键是否存在也是根据hashCode值来确定的。所以如果不重写hashCode的话,可能导致HashSet、HashMap不能正常的运作、
  如果我们将某个自定义对象存到HashMap或者HashSet及其类似实现类中的时候,如果该对象的属性参与了hashCode的计算,那么就不能修改该对象参数hashCode计算的属性了。有可能会移除不了元素,导致内存泄漏。

  总结一下关于hashcode的一些规定:

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

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

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

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


扩展:
在重写equals方法的时候,需要遵守下面的通用约定:
1、自反性。
对于任意的引用值x,x.equals(x)一定为true。
2、对称性。
对于任意的引用值x和y,当且仅当y.equals(x)返回true时,x.equals(y)也一定返回true。
3、传递性。
对于任意的引用值x、y和z,如果x.equals(y)返回true,并且y.equals(z)也返回true,那么x.equals(z)也一定返回true。
4、一致性。
对于任意的引用值x和y,如果用于equals比较的对象没有被修改的话,那么,对此调用x.equals(y)要么一致地返回true,要么一致的返回false。
5、对于任意的非空引用值x,x.equals(null)一定返回false。
重写hashCode方法的大致方式:
a、把某个非零常数值,比如说17(最好是素数),保存在一个叫result的int类型的变量中。
b、对于对象中每一个关键域f(值equals方法中考虑的每一个域),完成一些步骤:
1、为该域计算int类型的散列吗c:
1)、如果该域是boolean类型,则计算(f?0:1)。
2)、如果该域是byte、char、short或者int类型,则计算(int)f。
3)、如果该域是float类型,则计算Float.floatToIntBits(f)。
4)、如果该域是long类型,则计算(int)(f ^ (f>>>32))。
5)、如果该域是double类型,则计算Double.doubleToLongBits(f)得到一个long类型的值,然后按照步骤4,对该long型值计算散列值。
6)、如果该域是一个对象引用,并且该类的equals方法通过递归调用equals的方式来比较这个域,则同样对这个域递归调用hashCode。如果要求一个更为复杂的比较,则为这个域计算一个“规范表示”,然后针对这个范式表示调用hashCode。如果这个域的值为null,则返回0(或者其他某个常数)
7)、如果该域是一个数组,则把每一个元素当做单独的域来处理。也就是说,递归地应用上述规则,对每个重要的元素计算一个散列码,然后根据步骤下面的做法把这些散列值组合起来。
2、按照下面的公式,把步骤1中计算得到的散列码C组合到result中:
result = 31*result+c。
c、返回result。
可以通过org.apache.commons.lang.builder.HashCodeBuilder这个工具类来方便的重写hashCode方法。

o
粉丝 0
博文 500
码字总数 0
作品 0
私信 提问
加载中
请先登录后再评论。
hashCode和equals的区别

关注公众号,大家可以在公众号后台回复“博客园”,免费获得作者 Java 知识体系/面试必看资料。 有面试官会问:你重写过 hashcode 和 equals 么,为什么重写equals时必须重写hashCode方法?e...

osc_i6ddt53t
2019/08/07
4
0
Java equals 和 hashCode 的这几个问题可以说明白吗?

前言 上一篇文章 如何妙用 Spring 数据绑定? ,灵魂追问 环节留下了一个有关 equals 和 hashcode 问题 。基础面试经常会碰到与之相关的问题,这不是一个复杂的问题,但很多朋友都苦于说明他...

tan日拱一兵
2019/12/23
15
0
(转)喜马拉雅2018 Java面试题目

背景:将网上的题目整理下。 java基础 1:hashTable hashMap ConcurrentHashMap 的区别、数据结构、线程安全 2:equals和==区别, 重写equals一定要重写hashcode方法吗?为什么?hashcode方法...

osc_3rll7emc
2019/04/06
6
0
java学习-- equals和hashCode的关系

hashcode的目的就是在hashset或者hashmap等中比较两个对象相等时,减少equals的使用次数来提高效率 以下为摘录 java中hashcode和equals的区别和联系 HashSet和HashMap一直都是JDK中最常用的两...

osc_ktaf2wlb
2019/04/16
1
0
【Java】对象比较

前言 本篇博客主要梳理一下Java中对象比较的需要注意的地方,将分为以下几个方面进行介绍:<br> ==和equals()方法 hashCode()方法和equals()方法 Comparator接口和Comparable接口 ==和equals(...

osc_azfwmv8l
2018/12/01
2
0

没有更多内容

加载失败,请刷新页面

加载更多

平时使用的Lszrz到底是什么协议?说说Xmodem/Ymodem/Zmodem

XMODEM, YMODEM, and ZMODEM 由于平时使用rz/sz较多,r/s好理解,一个send一个receive。但是由不太清楚z是什么意思,故有此文。 sx/rx, sb/rb (b=batch)和sz/rz分别实现了xmodem,ymodem和z...

独钓渔
51分钟前
17
0
真正的强智能时代已经到来。道翰天琼认知智能机器人平台API大脑。

最近,我常说人工智能的寒冬快要来了,提醒业界要做好思想准备,但同时我也说:冬天来了,春天就不会远了…… 2019年6月我写了篇文章《深度学习的问题究竟在哪?》,说到深度学习的一个主要问...

jackli2020
今天
24
0
什么是控制型人格,控制型人格的筛查测试

一、 什么是控制性人格 拥有控制型人格的人,他们会尽力的隐藏自己的意图,但是又会使用很微妙的方式来利用周围人的弱点,进而占取便宜时,使他们能够得到自己想要的东西。这类人的控制欲非常...

蛤蟆丸子
今天
14
0
【Spring】Spring AOP 代理对象生成逻辑源码分析

1. spring aop案例(POJO注入) 1.0 被代理接口 TargetInterface /** * 被代理的接口 * @author Yang ZhiWei */public interface TargetInterface { void show(); String show......

ZeroneLove
今天
36
0
聊聊dubbo-go的gracefulShutdownFilter

序 本文主要研究一下dubbo-go的gracefulShutdownFilter gracefulShutdownFilter dubbo-go-v1.4.2/filter/filter_impl/graceful_shutdown_filter.go type gracefulShutdownFilter struct {......

go4it
今天
30
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部