终于搞懂为什么重写equals就需要重写hashCode了

为什么重写equals就需要重写hashCode

在阿里巴巴开发手册-华山版 中有一处强制规定:

【强制】关于 hashCode 和 equals 的处理,遵循如下规则:

1) 只要覆写 equals,就必须覆写 hashCode。

2) 因为 Set 存储的是不重复的对象,依据 hashCode 和 equals 进行判断,所以 Set 存储的对象必须覆

写这两个方法。

3) 如果自定义对象作为 Map 的键,那么必须覆写 hashCode 和 equals。

说明:String 已覆写 hashCode 和 equals 方法,所以我们可以愉快地使用 String 对象作为 key 来使 用。

我们可以在Object类中hashCode方法上面的注释得到以下几点:

  1. 同一个对象反复调用hashCode方法,返回的结果都是一致的。(前提是这个对象没被修改过)
  2. 如果使用equals方法比较得到两个对象相等,那么这两个对象去调用hashCode方法返回的值是相等的
  1. 两个对象的hashCode值相等,两个对象不一定相等。

由此,我们可以得出结论:

  1. 如果两个对象equals完结果相同,那么hashCode值肯定相等。
  2. 如果两个对象的hashCode值不相等,那么这两个对象也不相同。

我们在来看看Object类中的equals方法,equals是用来判断两个对象是否相等的,从官方注释可以知道它具备的性质:

  1. 它是自反的:对于任何非空引用值x , x.equals(x)应该返回true 。
  2. 它是对称的:对于任何非空引用值x和y , x.equals(y)应返回true当且仅当y.equals(x)返回true 。
  1. 它是可传递的:对于任何非空引用值x 、 y和z ,如果x.equals(y)返回true并且y.equals(z)返回true ,那么x.equals(z)应该返回true 。
  2. 它是一致的:对于任何非空引用值x和y , x.equals(y)多次调用始终返回true或始终返回false ,前提是没有修改对象的equals比较中使用的信息。对于任何非空引用值x , x.equals(null)应返回false 。

在注释中,有一句特别注意的话就是,每当重写此方法时,通常都需要重写hashCode方法,以维护hashCode方法的一般约定,即相等的对象必须具有相等的哈希码。

其实到了这里我们应该也能够明白了,hashCode和equals这两个方法根本就是配套使用的。那么要如何理解重写equals方法就必须要重写hashCode方法呢?

我们从Object类中可以看到,equals方法其实就是直接使用==进行比较的。所以当两个引用对象指向同一个在堆中被分配内存的实例时,则才会返回true,否则则返回false。

但是,Object类中的equals方法原本的功能在我们真实开发中是远远不够的,当两个对象引用的堆实例不同时,它就会认为这两个对象不相等;但是我们在真是开发中,我们认为两个对象是否相等,取决与其实例的属性是否相等。

举个栗子:

1
2
3
java复制代码A a1 = new A("123");
A a2 = new A("123");
a1.equals(a2);

上面这段代码,如果在没有重写equals方法的时候,得到的结果会是false。因为在堆中会是两个不同的实例,但是在真实开发中,我们想要比较的是属性内容是否相等,也就是说,此时a1和a2属性内容是一样的,所以a1.equals(a2)则需要返回true。这种情况其实也很常见,例如常见的String类,就是重写了equals方法,当内容相等则返回true。

那么又回到原来的问题,在hashCode方法的官方注释我们可以知道:如果两个对象equals完返回true,那么hashCode值肯定相等。所以,我们在重写equals的时候,则必须重写hashCode,保证其hashCode值相等,不然就违背了原来的原则了。

总之,只要重写了equals方法,那么就需要重写hashCode方法。我们看到Java中的String类,这个类在Java集合中用到很多,例如我们平时使用的HashMap/Set等等集合,都是经常性的使用String类型去当作key来进行使用的。

Ⅰ. 如果String没有重写equals,也就是继承了Object类的equals方法的话,则如果String类型为key的时候,相同的字符串,也可能会被当成两个不一样的key,从而难以辨别。

Ⅱ. 如果String重写了equals,没有重写hashCode。那么也会出现,同一个key出现在不同的位置,因为集合中常用哈希函数来计算key的位置,在没有重写hashCode的情况下,则同一个key会出现hashCode值不同而导致位置不同。

本文转载自: 掘金

开发者博客 – 和开发相关的 这里全都有

0%