equals 是什么
任何一个类都一定拥有 equals
这个方法,因为这是他们直接或间接继承自 Object 获得的
public boolean equals(Object obj) {
return (this == obj);
}
如果不进行重写,那么这个方法默认比较的就是两个对象的地址
而如果我们的需求是:两个对象即使地址不同,只要属性中的一部分相同,那么就认为这两个对象是相等的。(或在某种情况下认为相等)
那么我们就需要重写 equals
方法,因为 java 中的 ==
运算符比较的也是地址
equals
方法给了我们一个自由发挥的空间,让我们制定 “相等” 的规则
hashCode 是什么
hashCode
与 equals
一样都是来自 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()
的内容可以查看 ↓