为什么 Java 中重写 equals 一定要重写 hashCode


equals 是什么

任何一个类都一定拥有 equals 这个方法,因为这是他们直接或间接继承自 Object 获得的

public boolean equals(Object obj) {
    return (this == obj);
}

如果不进行重写,那么这个方法默认比较的就是两个对象的地址

而如果我们的需求是:两个对象即使地址不同,只要属性中的一部分相同,那么就认为这两个对象是相等的。(或在某种情况下认为相等)

那么我们就需要重写 equals 方法,因为 java 中的 == 运算符比较的也是地址

equals 方法给了我们一个自由发挥的空间,让我们制定 “相等” 的规则

hashCode 是什么

hashCodeequals 一样都是来自 Object,不同的是这是一个本地方法,因此我们看不到具体实现

public native int hashCode();

本地方法由 JVM 调用动态链接库实现的

一般情况下,hashCode 返回的是对象的存储地址经过运算后得到的整数,所以 hashCode 不相等的对象一定不是同一个对象,毕竟地址都不同

光看默认实现,好像与 equals 区别并不大,既然 hashCode 也能比较两个对象是否相等,那么为什么 JDK 不只留下一个方法呢?

因为 hashCode 相等并不代表两个对象一定相等,准确的说,hashCode 只能判断两个对象是不是不相等

因为 hashCode 是通过一系列算法得来的值,有重复的可能性,但如果连 hashCode 都不相等,那么肯定这两个对象是不相等的

注意,上面说了这么多“相等”,并不是“相同”的意思。两个比较的对象可能不是同一个对象,“相等”是我们认为某种意义上他们的值相等这一概念

那么 hashCode 用在什么地方呢

如果学过《数据结构》,那么一定对“哈希碰撞”不陌生

哈希表的性能是靠 hashCode 保障的,每一个元素都会有唯一的 hashCode,但是可能重复。

hashCode 相等时,会根据 equals 方法的结果判断两个对象是否真的相等

为什么重写 equals 一定要重写 hashCode

这个问题的答案可以分成两部分

什么时候会去重写 equals

equals 的作用是比较两个对象是否相等。而 equals 的默认实现是比较两个对象的地址

我们去重写这个方法意味着我们不希望根据地址来区分两个对象是否相等,而是根据他们的属性或其他的特点来判断

所以我们重写 equals ,是因为我们想制定这个类的 相等规则

为什么这时候要重写 hashCode

先记住一句话:两个相等的对象的 hashCode 也要是相等的,而两个 hashCode 值相等的对象却不一定相等

重写 equals 后判断对象是否相等的规则已经被改写,不再是根据地址判断。而 hashCode 的默认实现也是根据地址生成。如果我们不重写 hashCode 就会导致 equals 方法判断两个对象是相等的,但他们的 hashCode 不一定相等,违背了上面那句话

这会造成什么后果呢?

试想一下,你创建了一个 HashSet 对象,Set 集合的特点是不会重复,然而 相等 这一概念的比较是先比较 hashCode。这时我们放两个相等的对象进去,理论上应该只保留一个,但是由于他们 hashCode 不同,所以两个都会被放进去。

更多关于 hashCode()equals() 的内容可以查看 ↓

参考文章


文章作者: ❤纱雾
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 ❤纱雾 !
评论
  目录