哈希娱乐 行业新闻 党建先锋

为什么重写 equals 方法时必须同时重写 hashCode 方法哈希游戏?

发布时间:2025-11-07 14:37:23  浏览:

  哈希游戏作为一种新兴的区块链应用,它巧妙地结合了加密技术与娱乐,为玩家提供了全新的体验。万达哈希平台凭借其独特的彩票玩法和创新的哈希算法,公平公正-方便快捷!万达哈希,哈希游戏平台,哈希娱乐,哈希游戏

为什么重写 equals 方法时必须同时重写 hashCode 方法哈希游戏?

  为什么重写 equals 方法时必须同时重写 hashCode 方法?

  本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和 《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

  本文探讨了 Java 中 `hashCode` 方法的作用及其与 `equals` 方法的关系,解释了为什么重写 `equals` 方法时必须同时重写 `hashCode` 方法,并提供了如何正确重写 `hashCode` 方法的示例。

  本文由 Java 中常见的面试题「为什么重写equals方法时必须同时重写hashCode方法?」所引出。渐进式探讨关于hashCode的三个问题:hashCode方法的作用以及hashCode方法与equals方法的关系?为什么重写equals方法时必须同时重写hashCode方法?以及如何重写hashCode方法?

  我们知道,Java 中Object类是所有类的父类,而hashCode是Object类中定义的方法,所以每个类都会默认拥有一个hashCode方法。

  可以看到,hashCode方法用于生成一个整数,其是一个原生方法且使用@IntrinsicCandidate注解修饰,表示其实现完全依赖于 JVM,不同的 JVM 可能有不同的实现,常见的实现有使用伪随机数等。

  为什么Object类中要定义一个hashCode方法呢?此外我们还注意到,equals方法同样被定义在Object类中,这两个方法之间有什么关系呢?

  哈希表是存储键值(Key Value)对数据的一种数据结构。其通过将键映射到表中一个位置来访问数据,以加快查找速度,这个映射函数即被称为哈希函数(Hash Function)。Java 中的HashSet、Hashtable与HashMap均使用了哈希表。

  假定我们想实现一个Set,其存放的数据是不允许重复的,如果不借助哈希表,应该怎么来实现呢?

  我们能想到的一个办法是:当一个对象要被存入Set时,调用其equals方法与Set中的已有对象逐个进行比较,只有其与所有已有对象都不 Equal 时才可将其存入Set。而一般来说,equals方法的实现都比较重,需要将对象中的各个关键字段逐个进行比较,这在存放的对象特别多的时候效率会非常低下。

  而如果借助哈希表来实现呢?我们知道 Java 中HashSet是借用HashMap来实现的,HashMap是怎么在添加记录的时候提升效率的呢?

  可以看到,借助哈希表实现去重集合的话,因首先会判断哈希值是否相等,只有不相等时才会调用equals方法,所以只要哈希算法足够好,就会省去很多equals方法的调用。

  此外,哈希算法选用得当的话(理想的哈希算法是针对不同的对象,生成的哈希值可以均匀分布在整个int区间上,现实中是越接近越好),哈希表的检索效率会非常高,没有一次哈希冲突的话,检索记录的时间复杂度为O(1);最坏情况,hashCode全部相等,存储结构完全变成了一个链表,那么检索记录的时间复杂度会变为O(N)。

  总结该部分,我们可以看到:hashCode一般与equals一起使用,两个对象作「相等」比较时,因判断hashCode是判断equals的先决条件,所以两者使用必须遵循一定的约束。hashCode方法的注释上即说明了其与equals方法一起使用时需要遵循的三个通用约定:

  知道了hashCode方法的作用以及hashCode方法与equals方法的关系后,下面探讨一下为什么重写equals方法时必须同时重写hashCode方法。

  上面介绍了hashCode方法注释上列出的三个通用约定,equals方法的注释上也有这么一句话:「每当重写equals方法时,都需要重写hashCode方法,这样才没有破坏hashCode方法的通用约定,即:两个对象为 Equal 的话(调用equals方法为true), 那么这两个对象分别调用hashCode方法也需要返回相同的哈希值」。

  所以只重写equals方法不重写hashCode方法的话,可能会造成两个对象调用equals方法为true,而hashCode值不同的情形,这样即可能造成异常的行为。

  若不重写User类的hashCode与equals方法的话,则会使用Object类定义的默认实现,即:hashCode是 JVM 生成的一个伪随机数,equals比较的是两个引用的地址。

  该算法公式借用了 JDK 中「String.hashCode()」的实现逻辑,即:按属性依次计算哈希结果,当前属性的哈希结果为上一个属性的哈希结果乘以31并加上当前属性的哈希值(currentVal = 31 * previousVal + hash(currentPropertity)),直至所有属性计算完毕,最终的结果即为对象的哈希值。至于为什么要乘以31呢?原因是在于:其是一个奇素数,可以更好的保留信息,若是偶数的话,乘一个偶数相当于移位,超出的话会丢失信息;此外乘以31会被现代虚拟机优化为移位和减法来实现(31 * i == (i 5) - i),非常的高效。此外还可以直接调用Objects.hash(prop1, prop2, prop3, ...)来获取一个哈希值。

  重写equals方法的逻辑非常简单,即:判断是否为User对象且所有字段是否一致。