equals相等,HashCode方法却有可能不等(超详细)

今天继续研究hashcode与equals方法。
Q:hashCode方法的作用是什么?
A:在说hashcode方法的作用之前,我先说一下hashcode的特性。
1.hashcode特性体现主要在它的查找快捷性,在Set和Map这种使用哈希表结构存储数据的集合中。HashCode方法的就大大体现了它的价值,主要用于在这些集合中确定对象在整个哈希表中存储的区域。
2.如果两个对象相同,则着两个对象的equals方法返回的值一定为true,两个对象的HashCode方法返回的值也一定相同。
3.如果两个对象返回的HashCode的值相同,但不能够说明这两个对象的equals方法返回的值就一定为true,只能说明这两个对象在存储在哈希表中的一个桶中。
4.如果一个对象equals方法被重写,那么该对象的HashCode方法也应该被重写(具体原因下面再介绍)
说了这么多,接下来说hashcode的作用,在java中集合主要有三种,分别是List、Set、Map,其中Set和Map中都是用了哈希表结构,在Set中它是不能存储相同元素的,要说HashCode方法的作用先得说Set和Map中存储一个元素的过程,由于Set是不能够存储相同元素,则每次给set中添加元素的时候第一步先判断集合中是否存在该元素,如果存在则舍弃不进行存储,如果不存在则进行存储。在java中判断两个对象是否相等一般都使用equals方法进行判断。比如现在Set中已经存在1000个结构复杂的对象,再添加第1001个对象时,它会在集合中进行对比,看是否已经存在,如果存在则舍弃,结束添加操作。那如果不存在,则它会将要添加的对象与集合中1000个对象进行equals操作判断相等,最后再进行添加,那么这样程序的效率就会很低。于是java采用了哈希表的原理。哈希算法也叫散列算法,是将数据依据特定算法直接指定到一个地址上来。1.如果该物理地址上没有元素存在,则直接将该数据存储在该地址上,不用再进行任何比较了。2.如果该地址上存在元素,则进行比较如果相同则舍弃,不再进行存储与比较了。3.如果不相等的话则发生了hash冲突的情况,在set和map中的处理方式是在该位置上生成一根链表将产生的hash冲突并且equals不相同的对象,挂在这根链表上,则每次添加元素时就不用和整个集合中的元素进行比较,而只需要使用HashCode定位到该数据应该存储的地址上,然后与该地址上的对象进行比较即可。 采用哈希表以及HashCode的这种方法,会大大提高类似于Set和Map这种存储方式的效率。所以HashCode在上面的过程中主要扮演了寻找每个对象在集合中具体存储区域的功能,每个对象都可以计算出他们的hash码,按hash码进行分组,每个分组对应着一个存储区域,根据一个对象的hash码就可以确定该对象的存储区域,这样就大大减少了查询匹配元素的数量,大大提高了效率。
Q:为什么重写equals一定也要重写HashCode方法?
A:在java中equals方法用于判断两个对象是否相等,而HashCode方法在java中主要由于哈希算法中的寻域的功能(也就是寻找数据应该存储的区域的)。在类似于set和map集合的结构中,java为了提高在集合中查询匹配元素的效率问题,引入了哈希算法,通过某种算法及我们的HashCode方法得到对象的hash码,再通过hash码推算出数据应该存储的位置。然后再进行equals操作进行匹配,减少了比较次数,提高了效率。在集合做了优化之后进行判断元素相等的过程是这样的,首先判断两个对象的HashCode方法返回的值是否相等,如果相等然后再判断两个对象的equals方法,如果HashCode方法返回的值不相等,则直接会认为两个对象不相等,不进行equals方法的判断。有这样一个场景有两个Student对象,equals方法认为如果两个对象的学号相同则认为这两个对象相同。可是如果没有重写HashCode方法只重写了equals方法,此刻并不能实现我们的要求,它首先会判断HashCode方法返回的值是否相等,由于我们没有重写HashCode方法,此时返回的值是不同的,因此不会去判断我们重写的equals方法。而如果重写HashCode方法不重写equals方法也是同样的效果,不重写equals方法实际是调用Object方法中的equals方法,判断的是两个对象的堆内地址。而我们重写的HashCode方法认为相等的两个对象在equals方法处并不相等。因此重写equals方法时一定也要重写HashCode方法,重写HashCOde方法时也应该重写equals方法。
Q:为什么equals方法不相等而HashCode方法返回的值却有可能相同呢?
A:HashCode方法实际上是通过一种算法得到一个对象的hash码,这个hash码是用来确定该对象在哈希表中具体的存储区域的。返回的hash码是int类型的所以它的数值范围为[-2147483648-+2147483647]之间的,而超过这个范围,实际会产生溢出,溢出之后的值实际在计算机中存的也是这个范围的。比如最大值2147483647+1之后并不是在计算机中不存储了,它实际在计算机中存储的是-2147483648。在java中对象可以有很多很多通过new关键字来产生。而hash码也是通过特定算法得到的,所以很难或者说几乎没有什么算法在这个范围内在这个情况下不会不产生相同的hash码的。也就是说在上述情况下肯定是会发生哈希碰撞的,因此不同对象可能有相同的HashCode的返回值。也有人说Object方法中的HashCode方法是通过内存地址得来的,是唯一的。可是HashCode方法是共有的,也就意味着它是可以被程序员重写的。因此不同环境下实现HashCode的算法可能不同。因此equals方法返回结果不相等,而HashCode方法返回的值却有可能相同!
全部评论

相关推荐

07-13 14:45
南华大学 Java
北斗导航Compas...:英文和中文之间加个空格,有的句子有句号 有的没。其他没啥问题
点赞 评论 收藏
分享
屌丝逆袭咸鱼计划:心态摆好,man,晚点找早点找到最后都是为了提升自己好进正职,努力提升自己才是最关键的😤难道说现在找不到找的太晚了就炸了可以鸡鸡了吗😤早实习晚实习不都是为了以后多积累,大四学长有的秋招进的也不妨碍有的春招进,人生就这样
点赞 评论 收藏
分享
06-07 00:00
已编辑
腾讯_后端开发
点赞 评论 收藏
分享
不愿透露姓名的神秘牛友
07-11 12:31
以前小时候我最痛恨出轨、偷情的人,无论男女,为什么会出轨?现在我成了自己最讨厌的人,没想到分享的东西在牛客会被这么多人看,大家的评价都很中肯,我也认同,想过一一回复,但我还是收声了,我想我应该说说这件事,这件事一直压在我心里,是个很大的心结,上面说了人为什么出轨,我大概能明白了。我们大一下半年开始恋爱,开始恋爱,我给出了我铭记3年的承诺,我对她好一辈子,我永远不会背叛,我责任心太重,我觉得跟了我,我就要照顾她一辈子,我们在一起3年我都没有碰过她,她说往东我就往东,她说什么我做什么,她要我干什么,我就干什么!在学校很美好,中途也出过一些小插曲,比如男闺蜜、男闺蜜2号等等等。但我都强迫她改掉了,我...
牛客刘北:两个缺爱的人是没有办法好好在一起的,但世界上哪有什么是非对错?你后悔你们在一起了,但是刚刚在一起的美好也是真的呀,因为其他人的出现,你开始想要了最开始的自己,你的确对不起自己,21岁的你望高物远,你完全可以不谈恋爱,去过你想要的生活,你向往自由,在一起之后,你要想的不是一个人,而是两个人,你不是变心了,就像你说的,你受够了,你不想包容了,冷静几天是你最优的选择,爱人先爱己。
社会教会你的第一课
点赞 评论 收藏
分享
评论
点赞
1
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务