引言:
以下摘自JavaApi文档中,equals方法的说明:
注意红色部分,俺的翻译是:“注意:为了保持equals和hashCode之间那“不可告人的、很一般的” 联系,重写equals方法,普遍需要重写hashCode方法,无论何时;这表明,equal的对象必须有equal的hash码”
问题:由上面的"引言“,咱们是不是马上就有问题了。我想咱们的问题应该是一样的,那就是:
1、为什么重写equals方法,普遍需要重写hashCode方法?
2、为什么要让equals和hashCode之间保持联系?
3、equal和hashCode之间有什么联系的呢?
4、。。。。。。。
分析:
有问题是好的,没有问题的同学肯定是不是好同学;来吧,咱们一起来分析分析,搞不好能分析出来一些很深的宇宙观哦,(*^__^*) 嘻嘻……
不卖关子,直接给出关键点:这些问题的答案,研究一个HashMap(当然,也可以是Hashtable、HashSet等等)就能搞定,跟HashMap的查找、放入性能有关。
首先,咱们得先对HashMap的数据结构有个了解:HashMap底层的实现,所用到的数据结构有顺序表和链表,如下图(摘自网络):
大致了解结构后,咱们去看看HashMap的源码,就很明朗了:
分析以上代码可知:put方法是通过hash算法,得到key所对应顺序表中的位置,如果顺序表中对应的位置上没有Entry,则创建;如果有,直接将老的value替换为新的value。
如果我们重写了equals方法,也就是两个对象相等的定义被我们修改,但是却没有重写hashcode,导致,HashMap通过hashcode算法算出来的值不一样,也就是顺序表中的位置不一样,HashMap此时肯定会重写创建Entry,并不会将原来的value替换,这跟我们的想要达到的效果不一致。
(HashMap中get方法分析同上)
总结:
1)现在可以回答上述的问题了:当你重写equals了,也就是你重新定义了两个对象相等的条件,但是,你没有重写hashCode,其实,equals为true,看似相等的对象并不相等,因为他们的hashcode不一样;不如就让他们相等的彻底点,让他们的hashcode也相等吧。重写equals了,也重写下hashCode吧
2) 通过1),咱们理解了,为什么equals和hashCode这么有联系,我们最好也保持它们的这个联系
3)原来,它们的相互作用,相互的紧密联系,在HashMap、Hashtable等中体现出来了
当我们需要用自己的对象作为HashMap中key的时候,重写了equals,必须要重写hashCode。 其实,我强烈建议:任何地方,无论何时,重写equals必须重写hashCode。
引申:
研究HashMap不得不研究Hash算法,研究散列这种抽象数据类型,还有那经典的问题:hash碰撞或者hash冲突。其实,HashMap源码中的hash()、indexFor()两个方法已经很好地或者近乎完美的解决了这个问题。不过,这个问题,还是会出现,有兴趣的可以研究下,在此不多说
结尾:以上分析,可能不怎么具体,也不怎么全面,但是我觉得关键点是要理解:Java中对象相等的定义、HashMap的实现原理以及内部结构