此系列文章为本人对《Effective Java》一书的学习笔记,主要是记录对书中重点内容的理解。
既然有缘看到此文,那么希望能对你有所帮助。
本文对应原书第11条 覆盖equals时总要覆盖hashCode
原因
为什么重写equals
时必须重写hashCode
,其实就是为了基于哈希的集合能够正常运作,这类集合最典型的代表就是HashMap
。
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
这是HashMap
获取hash
的源码,可以看到它会调用key的hashCode
方法,获得原始哈希码后再经过扰动函数得到为其所用的新哈希码(扰动函数的作用这里不再赘述)
然后在实际使用时,通过哈希码进行第一次对比,通过后再比对地址,再调用equals
方法,所以哈希码对于HashMap
是效率的存在,它可以用最小的代价排除大量的非目标node。
若一个类重写了equals
方法,却没有重写hashCode
,可能会出现equals
返回true,而hashCode
结果却不同,这样就导致HashMap这样的集合无法正常使用
相应规范
- 在应用程序执行期间,只要对象的
equals
方法的比较操作所用到的信息没有被修改,那么这个对象的多次hashCode
调用必须返回同一个值; - 如果两个对象
equals
返回true,那么这两个对象的hashCode
返回结果必须相同; - 如果两个对象
equals
返回false,这两个对象的hashCode
返回结果不要求一定不同;
总结
由于我们在开发中,并不会手动的去重写hashCode
,所以对于其内部逻辑的修改一般不会接触,也不建议接触,所以使用自动化工具如AutoValue,lombok或者IDE帮我们完成就好(其中lombok直接将二者组合成了一个注解 @EqualsAndHashCode
)。
equals
和hashCode
一定是成对的进行重写,切记切记
水平有限,若文章中存在错误,恳请不吝赐教,这对我以及后面的读者都有重要意义