Object类中有这样一段说明,意思是建议我们equals方法和hashCode方法,或者一起重写,或者一起不重写,以维护hashCode的常规协定。
什么叫hashCode的常规协定呢?
我的理解就是:两个对象通过equals方法进行比较相等,它们分别调用hashCode方法时一定返回相同的整数;两个对象通过equals方法比较不相等是,不要求它们调用hashCode方法时必须返回不同的值,但是程序员应该意识到,在这种情况下,让它们返回不同的可以提高哈希表的性能。
怎么又涉及到哈希表的性能呢?
其实,我们一般不会直接调用hashCode方法,但是在集合中它们会被频繁的使用。重写equals方法时建议重写hashCode方法,是针对像Map、Set这种集合操作而言的。
我们创建一个类,谁都不能保证它什么时候会被放到集合中,所以,为了避免不必要的麻烦,建议重写equals方法的同时也重写hashCode方法,重写hashCode方法的同时也一起重写equals方法。
其实,equals方法与hashCode方法不一致会带来两个比较明显的问题。
一、理解困难,容易混淆
二、查找效率低下,也就是所谓的哈希表的性能会降低
这又从何说起呢?
我们知道,HashMap底层维护的是一个Entry类型的数组,向HashMap中添加键值对时,首先通过Key值计算出一个位置,该位置可能就是此元素将要放置的位置。如果发现,这个位置上没有元素,也就是为null,那么就直接将这个待添加的元素放置在该位置上。如果这个位置上已经有元素存在,那么接着通过equals方法比较这个待添加的元素Key与已经存在的这个元素的Key是否相等,不相等则执行添加操作,相等则返回旧值不执行添加操作。注意,这种情况下执行添加操作是将待添加的元素放置这个位置上,然后让这个待添加的元素指向已经存在的这个旧元素,如此在这个位置上就形成了链表。同理,取出元素是和添加类似,是通过给定对象的hashCode()方法计算出一个位置,然后在该位置上进行查找,找到就返回该元素,否则返回null。
明白了这个过程就好办了。
如果equals方法与hashCode方法一致,那么在HashMap所维护的那个Entry类型的数组中的每个位置上就只有一个元素,而不会形成链表,这样一来查找的性能就非常好,同时理解上也十分清晰明了。反之,如果二者不一致,就有可能造成难以理解或者查找的性能比较低。
下面以String类举例说明:
-
假设String类只重写了equals()方法,而没有重写hashCode()方法。也就是说其hashCode()方法仍然继承Object类的hashCode()方法。
看下面的代码段
HashSet set = new HashSet();
String s1 = new String("hello");
String s2 = new String("hello");
set.add(s1);
set.add(s2);
System.out.println(set.size()); //输出为2
此时,set中有两个元素,这两个元素的内容都为"hello",它们存储在数组中的不同位置上,因为
两个对象的hashCode()返回值不同。
如果我们将set中的元素迭代出来,就会看到两个"hello"。这就造成了理解上困难了,因为在我
们的记忆中set中的元素是不能重复的,但现在这个HashSet对象中却有两个"hello",这怎么解释
呢?虽然,它们实际上是两个不同的对象,但从表象上看它们确实是“一样的”,也只有构造这 个HashSet对象的我们知道,但是其它调用者却很难理解,这就是所谓的理解上的混乱。
-
假如String类只重写了hashCode()方法,而没有重写hashCode()方法。
同样,我们看上面那段代码
set中仍然有两个元素,但是相对于HashMap底层的那个Entry数组来说,这两个元素在相同的位置上,并且形成了链表,s2指向s1,因为s1和s2的hashCode()返回值相同,但通过equals()方法进行比较却返回false。
这样一来,查找起来就比较费劲了,因为要遍历链表。
我们知道,链表遍历只能是通过前一个元素找下一个元素。
我们这里是两个对象,找起来可能不那么费力,但是对象多了呢?链表长了呢?
这就是所谓的效率低。
这两点就造成了我们前面提到的哈希表的性能的下降。
综上所诉,虽然不强制要求重新equals方法时必须重写hashCode方法或者是重写hashCode方法必须重写equals方法,但是为了避免不必要的麻烦,建议二者要么一起重写,要么都不重写,以保持它们的一致性。
以上是作者的一点点理解,如有纰漏之处,还请多多指教。
本文转自 手不要乱摸 51CTO博客,原文链接:http://blog.51cto.com/5880861/1335139