手记

重写equals方法的时候为什么需要重写hashcode

简单说下HashMap的原理,HashMap存储数据的时候,是取的key值的哈希值,然后计算数组下标,采用链地址法解决冲突,然后进行存储;取数据的时候,依然是先要获取到哈希值,找到数组下标,然后for遍历链表集合,进行比较是否有对应的key。比较关心的有两点:

  1. 无论是 put 还是 get 的时候,都需要得到key的哈希值,去定位key的数组下标;
  2. 在 get 的时候,需要调用equals方法比较是否有相等的key存储过。


  反过来,分析上面的代码,Map的key是我们自己定义的一个类,可以看到,这里没有重写equal方法,更没重写hashCode方法,意思是map在进行存储的时候是调用的Object类中equals()和hashCode()方法。为此,由控制台输出hashCode码。 
  hashCode不一致,由此而拿不到数据。这两个key,在Map计算的时候,数组下标可能就不一致,就算数据下标碰巧一致,根据前面,最后equals比较的时候也不可能相等(很显然,这是两个对象,在堆上的地址必定不一样)。继续往下看,假如我们重写了equals方法,将这两个对象都put进去,根据map的原理,只要是key一样,后面的值会替换前面的值,接下来我们实验下:
  输出结果:
  instance value:1
newInstance value:2
你会发现同样的一个对象,为什么在map中存了2份,map的key值不是不能重复吗?没错,它就是存的2份,只不过在它看来,这2个的key是不一样的,因为他们的哈希码就是不一样的,可以打印看下输出的hash码确实不一样。那怎么办?只有重写hashCode()方法,更改后的代码如下:

可以看到,他们的hash码是一致的,且最后的结果也是预期的。

总结:
对于这个问题,是比较容易被忽视的,Map中存了2个数值一样的key,这个问题很严重。所以在重写equals方法的时候,一定要重写hashCode方法。
类似HashMap、HashTable、HashSet这种的都要考虑到散列的数据类型的运用。

1人推荐
随时随地看视频
慕课网APP