幻境栖息地

为什么 Java 中一个对象如果重写了 equals 方法后必须重写 hashCode 方法

更新于: 2021/09/20 15:33


首先这个是 Java 语言本身的语言规范要求,就这么简单。相关信息可以查看 Object 对象的 hashCode 方法的文档信息: Object Java Doc

接下来问题就是如果不这样做会发生什么?

因为有了上面的规范要求,Java 的一些功能在实现的时候就会依赖这条规则, 在假设规则没有被打破的情况下开发一些功能,这里拿 HashMap 的实现说明问题,HashMap 在使用 put 方法存储一个新元素的时候会先调用象的 hashCode 方法,利用这个方法的返回结果在确定这个对象应该存放在哪一个区域,如果 hash 后的结果和任何一个已经存在容器中的对象的 hash 结果不一样,那直接就保存这个对象,目前和 equals 方法没有任何关系。但是如果 hash 冲突了,就会遇到相同 hash 值的对象,然后在调用 equals 方法来确定这个对象是否真的和当前 hash 冲突的对象是不是同一个, 如果 equals 方法一样,就说明当前对象已经存在容器中, 如果不一样, 说明只是简单的hash冲突,会把他放存放在hash冲突对象的后面,有可能是链表有可能是红黑树。

从上面的逻辑可以看出来 HashMap 的工作原理完全依赖了这条规则, 那如果我们重写了 equals 方法, 但是没有重写 hashCode 方法,如果两个对象的 equals 的方法结果完全一致但是如果 hashCode 不一致, 这时候这两个对象如果存储在 HashMap 中,因为 hashCode 的结果完全不同, hashMap 就会当作两个对象不同,存放在不同的位置,并且 map 中的元素数量是 2,但是这两对象实际上是相同的。

其他依赖 hashCode 方法实现的功能有类似的问题,所以如果重写了 equals 方法,一定不要忘记重写 hashCode 方法,不然遇到 bug 后非常棘手。


浙ICP备16006181号-1