对java中equals跟hashCode函数的一些理解2(转)

对java中equals和hashCode函数的一些理解2(转)

一致性 
即如果两个对象相等的话,那么它们必须始终保持相等,除非至少有一个对象被修改了。 

在Object类equals函数的说明中的最后一段提到当我们改写equals函数的时候,通常都需要改写hashCode函数,后者同样在Object类中进行了定义,hashCode()函数返回一个对象的散列值(hash code),在java中有些集合类都是基于散列值的,如HashMap、HashSet、Hashtable等;它们都根据对象的散列值将其映射到相应的散列桶中。如Hashtable的put和get函数的实现如下所示: 

Java代码
  1.   public synchronized V get(Object key) {  
  2. Entry tab[] = table;  
  3. int hash = key.hashCode();  
  4. int index = (hash & 0x7FFFFFFF) % tab.length;  
  5. for (Entry<K,V> e = tab[index] ; e != null ; e = e.next) {  
  6.     if ((e.hash == hash) && e.key.equals(key)) {  
  7.     return e.value;  
  8.     }  
  9. }  
  10. return null;  
  11.    }  
  12.   
  13. ublic synchronized V put(K key, V value) {  
  14. // Make sure the value is not null  
  15. if (value == null) {  
  16.     throw new NullPointerException();  
  17. }  
  18.   
  19. // Makes sure the key is not already in the hashtable.  
  20. Entry tab[] = table;  
  21. int hash = key.hashCode();  
  22. int index = (hash & 0x7FFFFFFF) % tab.length;  
  23. for (Entry<K,V> e = tab[index] ; e != null ; e = e.next) {  
  24.     if ((e.hash == hash) && e.key.equals(key)) {  
  25.     V old = e.value;  
  26.     e.value = value;  
  27.     return old;  
  28.     }  
  29. }  
  30.   
  31. modCount++;  
  32. if (count >= threshold) {  
  33.     // Rehash the table if the threshold is exceeded  
  34.     rehash();  
  35.   
  36.            tab = table;  
  37.            index = (hash & 0x7FFFFFFF) % tab.length;  
  38. }   
  39.   
  40. // Creates the new entry.  
  41. Entry<K,V> e = tab[index];  
  42. tab[index] = new Entry<K,V>(hash, key, value, e);  
  43. count++;  
  44. return null;  
  45.    }  

因而hashCode函数极大地影响了这些集合类的正常工作。如果在改写完equals函数后,不相应改写hashCode函数,则可能会得不到想要的结果。如下例所示: 
Java代码
  1. Point p1 = new Point(12);  
  2. Point p2 = new Point(12);  
  3. Hashtable<Point, String> ht = new Hashtable<Point, String>();  
  4. ht.put(p1, "value");  
  5. System.out.println(p1.equals(p2));  
  6. System.out.println(ht.get(p2));  

由上面Point类的实现,p1和p2是相等的,第一个语句正常输出true;但是第二个语句输出的值是null,并没有得到期望中的“value”。导致这一问题的根本原因是Point类改写了equals函数,对相等的概念作了更改,但没有相应更改hashCode函数,使得两个相等的函数拥有不同的hashCode,违反了Object类关于hashCode的约定中的第2点,从而返回了错误的结果。 
在Object类中定义的几个hashCode约定如下: 
1. 在同一应用中,一个对象的hashCode函数在equals函数没有更改的情况下,无论调用多少次,它都必须返回同一个整数。 
2. 两个对象如果调用equals函数是相等的话,那么调用hashCode函数一定会返回相同的整数。 
3. 两个对象如果调用equals函数是不相等的话,那么调用hashCode函数不要求一定返回不同的整数。 
我们在改写equals 和 hashCode 函数的时候,一定要遵守如上3条约定,在改写equals的同时也改写hashCode的实现,这样才能保证得到正确的结果。

转自:http://lionheart.iteye.com/blog/135077