【Java面试】为什么重写equals方法必须同时重写HashCode方法?

简介: 【Java面试】为什么重写equals方法必须同时重写HashCode方法?

众所周知再JDK1.8之后,Java修改了String类型的底层源码,因为他们发现其实对于-128~127范围的字符更加常用,因此将底层的数组从char类型修改为了byte类型。

看到上面的方法可以发现,String类型的equals方法会先比较两个字符串的内存地址是否相等,如果是直接返回true,否则比较字符串的内容,如果内容相等返回true,否则返回false。

那么这和hashCode方法有什么关系呢?

总所周知,Java中所有的类都默认继承Object类,而Object类中有一个native的hashCode方法,因此所有的类都有一个native的hashCode方法

而hashCode方法在散列集合中会用到,比如HashTable、HashMap这些,当添加元素的时候,需要先判断元素是否存在,而如果直接使用equals方法去比较,那么效率非常低,此时通过的是对象的hashcode值进行取模后运算,如果table中没有这个对象相对应的hashcode的值,那么这个对象就可以存进去了,不用再进行任何比较。而如果已经存在了这个hashcode值,那么就需要进行equals方法进行对象比较,相同则覆盖,不相同直接插入。

所以这里就涉及到了一个冲突解决的问题,如果使用hashcode先判断对象是否相等,那么使用equals这个方法的次数就降低了,效率就自然提升了。

hashcode默认是JVM使用随机数生成的,两个随机对象,他们生成的hashcode值有可能相同。而如果这样子,再hash表中的提现就是所谓的hash冲突,通常使用链表或者线性探测来解决这个问题。

但是两个完全相同的对象,他们的内存地址指向同一个位置,也就是他们的hashcode一定是相同的。

那么在没有重写equals方法的情况下,x.equals(y)==true代表的就是x和y指向同一个内存地址,因为此时使用的是 == 进行判断。

那么他们的hashcode值也一定相同。

而如果重写了equals方法,但是没有重写hashCode方法,那么就会导致hashcode值可能不一样,而如果出现这种情况,就会导致这个类无法和所有的集合类一起工作。

对于散列集合,他们使用的是hashcode来判断是否是相同的,如果存储两个相同的对象,但是他们的hashcode值不同,那么就会导致这两个对象存储在hash表的两个不同的位置,然后当我们想要获取数据的时候,就会出现一个完全相同的对象,会存储在hash表的两个位置,就会破坏程序开发过程中我们约定俗成的规则,就会出现一些不可预料的错误。

所以在实际开发中,约定俗成:重写equals方法也必须重写hashCode方法。


相关文章
|
存储 Java 开发者
Java 中的 equals 方法:看似简单,实则深藏玄机
本文深入探讨了Java中`equals`方法的设计与实现。默认情况下,`equals`仅比较对象引用是否相同。以`String`类为例,其重写了`equals`方法,通过引用判断、类型检查、长度对比及字符逐一比对,确保内容相等的逻辑。文章还强调了`equals`方法需遵循的五大原则(自反性、对称性等),以及与`hashCode`的关系,避免集合操作中的潜在问题。最后,对比了`instanceof`和`getClass()`在类型判断中的优劣,并总结了正确重写`equals`方法的重要性,帮助开发者提升代码质量。
816 1
|
存储 Java C++
java中“==”和equals,究竟比的是什么
java中“==”和equals,究竟比的是什么
244 4
|
存储 Java C++
java中“==”和equals,究竟比的是什么
java中“==”和equals,究竟比的是什么
189 3
java中“==”和equals,究竟比的是什么
|
Java 编译器
在Java中,关于final、static关键字与方法的重写和继承【易错点】
在Java中,关于final、static关键字与方法的重写和继承【易错点】
271 5
|
Java 编译器 数据安全/隐私保护
Java 重写(Override)与重载(Overload)详解
在 Java 中,重写(Override)和重载(Overload)是两个容易混淆但功能和实现方式明显不同的重要概念。重写是在子类中重新定义父类已有的方法,实现多态;重载是在同一类中定义多个同名但参数不同的方法,提供多种调用方式。重写要求方法签名相同且返回类型一致或为父类子类关系,而重载则关注方法参数的差异。理解两者的区别有助于更好地设计类和方法。
1238 2
|
Java
描述 Java 中的重载和重写
【8月更文挑战第22天】
149 0
|
存储 Java
【IO面试题 四】、介绍一下Java的序列化与反序列化
Java的序列化与反序列化允许对象通过实现Serializable接口转换成字节序列并存储或传输,之后可以通过ObjectInputStream和ObjectOutputStream的方法将这些字节序列恢复成对象。
|
存储 算法 Java
大厂面试高频:什么是自旋锁?Java 实现自旋锁的原理?
本文详解自旋锁的概念、优缺点、使用场景及Java实现。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
大厂面试高频:什么是自旋锁?Java 实现自旋锁的原理?
|
存储 缓存 算法
面试官:单核 CPU 支持 Java 多线程吗?为什么?被问懵了!
本文介绍了多线程环境下的几个关键概念,包括时间片、超线程、上下文切换及其影响因素,以及线程调度的两种方式——抢占式调度和协同式调度。文章还讨论了减少上下文切换次数以提高多线程程序效率的方法,如无锁并发编程、使用CAS算法等,并提出了合理的线程数量配置策略,以平衡CPU利用率和线程切换开销。
面试官:单核 CPU 支持 Java 多线程吗?为什么?被问懵了!
下一篇
开通oss服务