关于equals和hashCode方法
本篇文章记录学习方法和hashCode()方法的内容。
什么是hashCode
通常所说的hashCode是一个经过哈希运算后的整型值,这个哈希运算的方法,定义在Object类中,通过一个本地方法hashCode()来实现(在hashMap中还会有一些其他的运算)。
要了解这个方法到底是什么作用,最有效的方法就是直接看源码注释。
返回当前对象的一个哈希值。这个方法用于支持一些哈希表,例如hashMap。
通常来讲,它有一下一些约定:
- 若对象的信息没有被修改,那么,在一个程序的执行期间,对于相同的对象,不管调用多少次hashCode方法,都应该返回相同的值。当然,在相同程序的不同执行期间,不需要保持结果的一致。
- 若两个对象的equals()方法返回值相同,那么,他们调用各自的hashCode方法时,也必须返回相同的结果。
- 当两个对象的equals()方法返回值不同时,那么他们的hashCode方法不用保证必须返回不同的值。但是,我们应该知道,在这种情况下,最好也设计成hashCode返回不同的值。因为,这样做有助于提高哈希表的性能。
实际情况下,Object类的hashCode方法在不同的对象确实返回了不同的哈希值。这通常是通过把对象的内部地址转换成一个整数来实现的。
这里所说的内部地址就是物理地址。需要注意的是,虽然hashCode值是依据它的物理地址而得来的。但是,不能说hashCode就代表对象的内存地址。
hashCode有什么用
在哈希表中,通过key计算出它的hashCode值,再进行处理就可以确定它在哈希表中的位置,这样,在查询时,就可以直接定位到当前元素,提高查询效率。对于要插入的一个新元素,先去计算它的hashCode值,如果此位置没有元素,那么就直接插入即可。如果此位置已经有值,可以通过equals()方法比较它们是否相等,不等则也插入到这个位置(可以用链表形式存放)。所以,hashCode提高了查询,插入元素的效率。
equals和==的区别
equals比较的是内容,而 == 比较的是地址。
equals()方法是定义在Object类中的。
可以看到,它的默认实现,就是 == ,用来比较两个对象的内存地址是否相等。如果一个对象不重写equals,那么效果和 == 是一样的。
因此,在使用自定义类的对象时,如果要让两个对象的内容相同时认为对象时相同的,则需要重写equals方法。
为什么要重写equals和hashCode
前面已经说明为什么重写equals,重写hashCode就涉及到Map和Set(底层其实也是Map)的内容了。
以hashMap jdk1.8的源码来看,如put方法。

image-20211203210055456
可以看到,在插入元素时,代码中多次进行hash值的比较,只有当hash值相等时,才会去比较equals()方法。当哈希值和equals比较都相等时,才会覆盖元素。get方法也是如此。
只有当hashCode和equals都相等时,才认为是同一个元素。
重写hashCode和equals的目的,就是为了方便哈希表这样的结构快速的查询和插入,不重写,则无法比较元素,可能造成元素位置错乱。
重写了equals,就必须重写hashCode
在JDK源码注释第二点就说明了这一点。如果不重写hashCode,对于我们自定义的类,创建的两个内容相同的对象,将其中一个对象加入到hashmap中,另一个对象调用其hashCode查找位置仍能插入成功,这是不正确的。
还需要注意的是,讲对象插入到了hashMap后,不要在使用过程中,改变对象的值,这样会导致hashCode值发生改变,无法再获取到插入的值。
String类具有不可变性,所以我们经常使用String类作为hashMap的key值。
hashCode相等,equals一定相等吗
显然不是。在源码中,当通过hashCode值处理后计算出来的位置相等(产生哈希碰撞)时,还需要比较它们的equals,才能确定是否是同一个对象。因此,hashCode相等时,equals不一定相等。
反过来,equals相等,那么hashCode一定相等吗?是一定的。equals都相等了,那么在hashMap中认为它们是同一个元素,那么hashCode值必须保证相等。
总结
hashCode相等,equals不一定相等
hashCode不等,equals一定不等
equals相等,hashCode一定相等
equals不等,hashCode不一定不等
在源码注释第三点也提到,当equals不等时。不必保证它们的hashCode不等。但是为了提高哈希表的效率,最好设计成不等。因为,我们既然知道它们不相等了,那么当 hashCode 设计成不等时。只要比较hashCode 不相等,我们就可以直接返回 null,而不必再去比较 equals了。这样,就减少了比较的次数,无疑提高了效率。
关于equals和hashCode方法
https://twilight218.github.io/2021/11/25/关于equals和hashCode方法/