常背八股文的经常会看到这样一道经典面试题:为什么重写了equals()就一定要重写hashCode()?

首先,我们要知道这两个方法是做什么的,Java秉承着万物皆对象的理念,而Java中所有对象向上追溯,会有一个共同的祖先--Object类,而equals和hashCode正是Object类中的两个方法,足以证明其重要性

equals方法用于比较两个对象是否“相等”,这里经常会有人用equals和==作比较,对于引用数据类型,==符号是比较两者内存地址,而不重写的equals在底层就是直接调用==,也是比较内存地址,但有些时候我们需要比较两个对象的属性值是否相同,所以需要自己重写equals
想要了解hashCode方法,我们需要先了解hash算法。如果我们使用数组或链表去存储数据,在数据量大时会产生增删或者查询上的性能问题,所以集合应运而生,这里以Java中常用的HashSet为例(HashMap原理相同),HashSet的底层是一个数组,当我们想要向集合中添加一个元素时,会先调用hashCode计算该元素的hash值,并根据该hash值定位到数组的某个位置,如果该位置存在数据,就调用equals方法比较这两个对象,如果相同则直接删除(在HashMap中是覆盖),如果不同则加入链表,即两个元素在同一个位置,只不过是变成了链表。在查询某个元素时也是通过hash快速定位来查询。

所以我们可以回答这个问题了,我们从两个反例来回答:

  • 重写equals,没重写hashCode
  • 没重写equals,重写hashCode

重写equals,没重写hashCode,会造成什么问题?不重写的hashCode方法是根据对象的内存计算hash值的,也就是说,不考虑哈希碰撞的情况下,两个“相同”的对象hash值是不同的,现在我向HashSet中插入两个相同的元素,但由于hash值不同导致这两个元素均被插入,所以去重失败。

重写hashCode,不重写equals,会造成什么问题?现在我向HashSet中插入两个相同的元素,由于重写了hashCode,会导致两个元素hash值相同,但我们会继续调用equals方法来确定两个对象是否相同(这里是加一层保险,解决哈希碰撞问题),equals对象比较二者地址,返回false,所以两个元素都添加成功,去重失败。

综上,二者需要一起重写,不然所有和hash有关的地方,都会出现潜在的问题。


Echo
2 声望1 粉丝