深入剖析hashCode和equals的区别及大厂面试题

首先我们要知道,equals()和hashCode()都属于Object类,而Object类是所有类(包括Class)的父类。

搞清楚这一点,再分别解析equals和hashCode,然后作出对比。最后,给出关于equals和hashcode重要面试题及答案。

equals()解析

  • 作用:用于引用数据类型,判断一个对象是否等于另一个对象,可以重写 equals 方法自定义比较规则。

  • ==和equals的区别

    • 如果变量是基本数据类型,那么使用==比较变量的值。
    • 如果变量是引用数据类型,==仍然比较变量的值(不忘初心),只不过这个值是对象的地址。
    • equals只能作用于引用数据类型。 equals如果没有重写,比较的是引用变量的值,即对象地址。equals重写之后,比较的是对象的内容。例如使用equals比较String的value值是否相等。

hashCode()解析

  • 作用:hashCode() 的作用是获取哈希码,也称为散列码,其作用是将对象的地址值(即引用变量)映射为integer类型的哈希值。这个哈希码的作用是确定该对象在哈希表中的索引位置。

注意,字符串(String类型)可能有相同的散列码。这是由于String类型中重写了hashcode方法。 看下图可知,String类型的字符串值是保存在value中的。而value会保存在字符串常量池中。 alt

alt

比如,

s1 = "123";
s2 = "123";

s1和s2的引用变量,即对象的地址,是不同的。但由于s1和s2的引用对象的value数组值是相同的。故,在计算哈希值时,s1和s2的就会得到相同的哈希值。

hashCode()和equals()面试题解析

1. hashCode() 和 equals() 两种方法之间有什么关系?

答:

为了在集合类HashMap或HashSet中正确使用散列码,需同时重写 equals 和 hashCode 方法。

两对象比较时,先比较hashCode后比较equals。equals 相同时 hashCode 必相同,但 hashCode 相同时 equals 未必相同。hashCode 是两个对象相同的必要不充分条件。 即:

       equals相同<=>对象相同

       对象相同=>hashcode相同

    逆否命题:hashCode不同=>对象不同

2. 为什么hashcode相同时,equals不一定相同?

答:有时候不同的对象,hashcode的值可能也会相同,例如:

alt

所以说,hashCode()并不可靠。 equals由于比较的是对象的值,值相同与否是可以确定的,所以是可靠的。

3. 为什么不直接equals比较值是否相同,而先要计算hashCode?

答: hash算法是二进制算法,计算式本质是二进制,所以hash算法速度很快。如若hashCode不同则可直接存储不用equlas比较。所以先计算hashCode大大加快了存储速率。

4. 为什么重写equals后必须重写hashcode? 答:

Object类的equals()方法上方的注释里有写到:当我们将equals方法重写后有必要将hashCode方法也重写,这样做才能保证不违背hashCode方法中"相同对象必须有相同哈希值"的约定。

由此可见,重写equals后必须重写hashcode是为了保证重写后的equals方法认定相同的两个对象拥有相同的哈希值。

至于equals相同hashcode也必须相同的原因,是为了与Java集合配套使用。

我们可以以hashSet实现去重功能为例,hashSet底层是通过HashMap来实现的,查看源码可以发现HashMap中的Hash()方法,是调用了key.HashCode()。

alt

我们假设自定义一个学生类型Student,且Student只重写了equals方法。然后,new出两个属性值完全一样的对象,将其先后添加到HashSet中。 查看HashMap中的putVal()方法可知, alt

会将传入学生对象的hash值与(数组长度-1)进行&操作,得到数组的下标值。但是由于学生类型,没有重写hashCode,则其hashcode()方法默认是通过对象的地址值的得出。

由于两个学生对象的地址值不同,因此哈希值不同。那么,根据哈希值计算出的索引位置就会不同,则会将两个学生对象存入不同的数组位置。但是,由于equals是根据学生信息计算的,所以equals是相同的。这就违背了hashset的去重功能(hashset不会将相同的对象存到数组中)。因此,必须重写HashCode()方法。

5.会自定义子类重写equals吗?

答:示例如下

alt

好了,到此为止,关于hashcode和equals的知识点大家应该有个深刻的理解了。


您宝贵的点赞,是我更新的动力!


以上内容出自本人整理的面试秘籍。 


https://www.nowcoder.com/share/jump/4205669601722747214496

如果有帮助不到你,麻烦给我点下方🌸支持我,谢谢!

请关注我,以便及时获取最新内容!

#Java##软件开发2024笔面经##软件开发笔面经##秋招#
全部评论

相关推荐

今天 07:38
已编辑
门头沟学院 Java
2.4&nbsp;一面2.6&nbsp;二面2.9&nbsp;三面(hr面)2.13&nbsp;oc1.15号收到面试电话那会就开始准备,因为一开始没底所以选择推迟一段时间面试,之后开始准备八股,准备实习可能会问的东西,这期间hot100过了有六七遍,真的是做吐了快,八股也是背了忘,忘了背,面经也看了很多,虽然最后用上的只有几道题,可是谁知道会问什么呢自从大二上开始学java以来,一路走来真的太痛了,一开始做外卖,点评,学微服务,大二下五六月时,开始投简历,哎,投了一千份了无音讯,开始怀疑自己(虽然能力确实很一般),后来去到一家小小厂,但是并不能学到什么东西,而且很多东西都很不规范,没待多久便离开,大二暑假基本上摆烂很怀疑自己,大三上因为某些原因开始继续学,期间也受到一俩个中小厂的offer,不过学校不知道为啥又不允许中小厂实习只允许大厂加上待遇不太好所以也没去,感觉自己后端能力很一般,于是便打算转战测开,学习了一些比较简单的测试理论(没有很深入的学),然后十二月又开始继续投,java和测开都投,不过好像并没有几个面试,有点打击不过并没有放弃心里还是想争一口气,一月初因为学校事比较多加上考试便有几天没有继续投,10号放假后便继续,想着放假应该很多人辞职可能机会大一点,直到接到字节的面试,心里挺激动的,总算有大厂面试了,虽然很开心,但同时压力也很大,心里真的很想很想很想进,一面前几天晚上都睡不好觉,基本上都是二三点睡六七点醒了,好在幸运终于眷顾我一次了(可能是之前太痛了),一面三十几分钟结束,问的都不太难,而且面试官人挺好但是有些问题问的很刁钻问到了测试的一些思想并不是理论,我不太了解这方面,但是也会给我讲一讲他的理解,但是面完很伤心觉得自己要挂了。但是幸运的是一面过了(感谢面试官),两天后二面,问的同样不算难,手撕也比较简单,但也有一两个没答出来,面试官人很好并没有追问,因为是周五进行的二面,没有立即出结果,等到周一才通知到过了,很煎熬的两天,根本睡不好,好在下周一终于通知二面过了(感谢面试官),然后约第二天三面,听别的字节同学说hr面基本上是谈薪资了,但是我的并不是,hr还问了业务相关的问题,不过问的比较浅,hr还问我好像比较紧张,而且hr明确说了还要比较一下,我说我有几家的面试都拒了就在等字节的面试(当然紧张,紧张到爆了要),三面完后就开始等结果,这几天干啥都没什么劲,等的好煎熬,终于13号下午接到了电话通知oc了,正式邮件也同时发了,接到以后真的不敢信,很激动但更重要的是可以松一口气了,可以安心的休息一下了终于可以带着个好消息过年了,找实习也可以稍微告一段落了,虽然本人很菜,但是感谢字节收留,成为忠诚的节孝子了因为问的比较简单,面经就挑几个记得的写一下一面:1.实习项目的难点说一下2.针对抖音评论设计一下测试用例3.手撕:合并两个有序数组二面:1.为什么转测开2.线程进程区别,什么场景适合用哪个3.发送一个朋友圈,从发出到别人看到,从数据流转的角度说一下会经历哪些过程4.针对抖音刷到广告视频设计测试用例5.手撕:无重复字符的最长字串
查看8道真题和解析
点赞 评论 收藏
分享
钱嘛数字而已:辅导员肯定不能同意,不然你出事了,他要承担责任。但是,脚和脑子都长在你自己身上,使用它还需要向辅导员报告么? 辅导员必须按流程拒绝你,然后你拿出成年人的态度,做自己的选择。
点赞 评论 收藏
分享
评论
5
8
分享

创作者周榜

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