【有标题】为什么使用容器重写equals一定要重写hashcode?


前言

前言得说点什么,那就说点什么:

这个问题其实是在看equals和==区别的时候开始
主要是了解了equals()方法后就会提到hashcode()方法
主要是记不住,
那就写吧

前言就说这么多吧


提示:以下是本篇文章正文内容,下面案例可供参考

一、所以equals和==有什么区别?

== 对于基本类型来说是值比较,对于引用类型来说是比较的是引用地址;

equals 默认情况下是引用地址比较

我们用String来举例子
在这里插入图片描述

public static void main(String[] args) {
	String zym = "sao0";
	String lyh = "sao0";
	String wyx = new String("sao0");
	
	System.out.println(zym == lyh);//第一个比较
    System.out.println(lyh == wyx);//第二个比较
    
    System.out.println(zym.equals(lyh));//第三个比较
    System.out.println(lyh.equals(wyx));//第四个比较
}

先看运行结果吧
在这里插入图片描述
啊那这时候就有人问了,前面说了“==”对于引用类型是比较地址,那“zym”和“lyh”虽然都是“sao0”,但比较的是地址又不是值,为什么会一样呢?
那就不得不不得不提一嘴JVM了

JVM为了提高性能和减少内存开销,为字符串开辟一个字符串常量池,有点像一个缓存区
创建字符串常量时,首先坚持字符串常量池是否存在该字符串:
	1.存在该字符串,返回引用实例
	2.不存在该字符串,实例化该字符串并放入常量池中

所以,“zym”和“lyh”都是指向JVM堆的常量池中的“sao0”,所以比较得结果为true,
啊这时候“wyx”跳出来了,为什么我和“lyh”明明都是“sao0”,wyx= =lyh就为false呢?
别着急,看下面这张图
在这里插入图片描述
new出来的“wyx”并没有在常量池中,所以使用wyx和lyh指向的地址不同,结果就为false
换句话来说就是:
wyx和lyh不是同一个sao0
在这里插入图片描述

解决了“==”的疑问,我们来说说equals
诶,这时候又有人问了,你前面都说了equals默认情况下是引用地址比较,那第三和第四结果也应该是true false啊,为什么结果是true true呢?

嗯,默认情况确实是这样,但是!!!诸如String,Integer等都会重写equals方法,把equals变成了值比较。
现在我们返回去看,zym lyh wyx其实都是sao0!,所以使用被String重写后的equals方法比较,结果都为ture。

应该清楚equsls了吧,在不清楚就不礼貌了



二、hashCode是什么?为什么要和equals一起讨论?

1.hashCode简介

首先,hashcode()是用来查找的,查找对象储存地址。
Object类的作者在注释的最后一段的括号中写道:将对象的地址值映为integer类型的哈希值。

所以通俗来讲hashCode()就是在Object中的一个获取散列码并返回一个int整数的方法。

2.hashCode存在的意义

我们先来看一套关于equals和hashcode的描述(丝滑连招)

  • 如果equals为true,hashcode一定相等;
  • 如果equals为false,hashcode不一定不相等;
  • 如果hashcode值相等,equals不一定相等;
  • 如果hashcode值不等,equals一定不等;

嗯,看到这儿的时候我就在想,那我用hashCode干嘛?
直接建一个集合,把要存的对象全挨个放进去,然后要找的时候直接equals不就好了?
在这里插入图片描述

只能说,我雀氏年轻了,
我们以HashSet来举例:
对象加入HashSet的时候,HashSet会先计算对象的hashcode值来判断对象加入的位置,看该位置是否有值?
–如果没有,把对象放进该位置。
–如果有,这时候再调用equals方法来检查两个对象是否真的相同?
----如果相同,HashSet就不会让对像加入
----如果不同,HashSet就会放对象散列到其他位置(参考线性探查,或者双散列探查)

看到这儿大伙儿应该就知道了,这样可以减少equals的次数,过了hashcode那关再过equals这关,大大提高了执行速度。



三、为什么容器中重写equals一定要重写hashcode?

我们前面已经举过例子了,equals重写后比较的是对象的内容,没重写equals比较的是对象再空间中的存储地址。如果重写了equals不重写hashcode,所以会导致equals相等而推出两个对象相同,而默认的hashcode方法是根据对象的内存地址经哈希算法得来的,所以hashcode不等的逻辑错误。

再举个例子

Person lzy1 = new Person("lzy"1)Person lzy2 = new Person("lzy"1)System.out.println(lzy1.equals(lzy2))

结果肯定是true
假如只重写equals而不重写hashcode,那么Person类的hashcode方法就是Object默认的hashcode方法,由于默认的hashcode方法是根据对象的内存地址经哈希算法得来的,很显然lzy1与lzy2在内存中地址不一样所以hashcode不一定相等,然而equals为true,所以导致逻辑错误。所以重写equals后需要重写hashCode方法。



总结

如果您从头到尾看完了
不难得出:

zym,lyh是sao0 
而wyx是不同于lyh的sao0 
和lzy是1

的结论。

参考文献:
https://blog.csdn.net/xl_1803/article/details/80445481
https://blog.csdn.net/HFish24/article/details/107652227
https://blog.csdn.net/xingyu19911016/article/details/122011089

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值