为什么重写hashCode 还需要重写 equals方法
(或者两者反过来说)
众所周知,根据生成的哈希码将数据离散开来,可以是存取元素更快。调用 Object.hashCode() 生成哈希值;由于比可避免地会存在哈希值冲突的情况,因此当 hashCode 相同时,还需要再调用 equals 进行一次值的比较;但是,若 hashCode 不同,将直接判定 Object 不同,跳过 equals,这加快了冲突处理效率。
首先可以了解下,hashCode 是一个本地方法,其相关源码:
VM_ENTRY(joint, JVM_IHashCode(JNIEnv* env, jobject handle))
JVMWrapper(“JVM_IHashCode”);
return Handel == NULL ? 0 : ObjectSynchronizer :: FastHashCode
(THREAD, JNIHandles :: resolve_non_null(handle));
VM_END
从代码上可以分析到hashCode 就是根据对象的地址进行相关计算得到 int 类型的数值。
mark = monitor->header();
assert(mark->is_neutral(), “invariant”);
hash = mark->hash();
intptr_t hash() const {
return mask_bits(value() >> hash_shift, hash_mask);
}
关于哈希码的相关知识点
- 解决冲突的方法:
-
开放式地址法
-
线性探索再散列
例:用线性探测再散列实现 14、5、21、16、17、15,在0 ~ 10的存储空间中的存放散列函数为H(key)=key%9。
0 1 2 3 4 5 6 7 8 9 10 14 5 15 -
H(14)=14%9=5
-
H(5)=5%9=5(冲突) 则(5+1)%11=6
…(省略)
-
H(15)=15%9=6(冲突) 则(6+1)%11=7
-
-
二次探索再散列
遇上差不多,只是平方了
d1 = H(key) di = (d1 + i2) % m i = 1,2,3…
-
随机探索再散列
d1 = H(key) di=(d1+R)%m R是给定的随机数
-
-
链地址法
-
每个哈希表节点都有一个next指针,多个哈希表节点可以用next指针构成一个单向链表,被 分配到同一个索引上的多个节点可以用这个单向链表进行存储.
继上题条件
将每个冲突的元素放置对应位置的链表后
-
填充因子:存储的数据 / 存储空间长度 = 7 / 11 (越小冲突可能性越小,越大冲突可能性越大)
-
哪里大佬发现有问题的跟小弟说,小弟立马改
被问到重写hashCode后为什么还要重写equals
感觉这么问会好说一点,因为可以说即使两个对象的 hashCode 相等,但未必两者内容也相同,这时候需要重写 equals 来判断对象的内容是否相同。
关于 equals 相关知识点可以查看 【equals 与 == 有什么不同】
但是被问到重写 equals 重写后有什么必要重写 hashCode 该怎么回答
在此之前是比较懵的,因为当时还没彻底了解过 equals,认为
可以举个例子 Set 例子,我们编写一个 MyTest 类重写 equals 没重写 hashCode,new出三个对象,分别添加到Set中。
import java.util.*;
public class Main {
public static void main(String[] args) {
Set<MyTest> set = new HashSet<>();
set.add(new MyTest(1,"baven"));
set.add(new MyTest(1,"baven"));
set.add(new MyTest(1,"baven"));
System.out.println(set.size()); // 大小为 3
}
}
class MyTest{
int id;
String name;
MyTest(int id, String name){
this.id = id;
this.name = name;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
MyTest myTest = (MyTest) o;
return id == myTest.id &&
Objects.equals(name, myTest.name);
}
}
最终大小并不为1,而是为3。原因是因为,new出的对象地址都是不相同的,根据 equals 的特性,虽然比较得出内容相等但是弟子不同。
所以这时候有一条要求:
如果两个对象的 equals 的结果是相等的,则两个对象的 hashCode 的返回结果也必须相同。
注:是必须,而不是一定或是什么判断得出的语气,是必须!铁要求!
所以这时候,在重看Set的这个例子,如果重写了hashCode,按照要求得出哈希码也相等,那么Set的大小就会为 1。
祝早日new到对象