淺談equals和hashcode

關鍵字: equals , hashcode

轉自:http://www.sunxin.org/forum/thread/19720.html

先談equals。
equals是Object類提供的方法之一,衆所周知,每一個java類都繼承自Object類,
所以說每一個對象都有equals這個方法。而我們在用這個方法時卻一般都重寫這個方法,why?

Ok,先看一個Object類中equals()方法的源代碼:

  1. public boolean equals(Object obj) {   
  2.     return (this == obj);   
  3. }  

      從這個方法中可以看出,只有當一個實例等於它本身的時候,equals()纔會返回true值。通俗地說,此時比較的是兩個引用是否指向內存中的同一個對象,也可以稱做是否實例相等。而我們在使用equals()來比較兩個指向值對象的引用的時候,往往希望知道它們邏輯上是否相等,而不是它們是否指向同一個對象——這就是我們通常重寫這個方法的原因。

      在程序員之家論壇中有這樣一篇文章《全面理解Java中的String數據類型》(鏈接http://www.phome.asia/forum/thread/19667.html) ,在這篇文章中,String s1 = new String(“kvill”),String s2 = new String(“kvill”); s1.equals(s2)爲ture,說明String類中已經重寫了equals()方法,如果不重寫equals()方法,那麼s1.equals(s2)默認比較兩個對象所指向的內存地址是否相同,返回值必然爲false。

       重寫equals()方法看起來非常簡單,但是有許多改寫的方式會導致錯誤,並且後果非常嚴重。要想正確改寫equals()方法,你必須要遵守它的通用約定。下面是約定的內容,來自java.lang.Object的規範,equals方法實現了等價關係,以下是要求遵循的5點,這5點都是當年數學的概念啊……,呵呵,且看:

1. 自反性:對於任意的引用值x,x.equals(x)一定爲true。 

2. 對稱性:對於任意的引用值x 和 y,當x.equals(y)返回true時,y.equals(x)也一定返回true。 

3. 傳遞性:對於任意的引用值x、y和z,如果x.equals(y)返回true,並且y.equals(z)也返回true,那麼x.equals(z)也一定返回true。

4. 一致性:對於任意的引用值x 和 y,如果用於equals比較的對象信息沒有被修改,多次調用x.equals(y)要麼一致地返回true,要麼一致地返回false。

5. 非空性:對於任意的非空引用值x,x.equals(null)一定返回false。

      瞭解了equals重寫,我們再看hashCode()這個方法,hashcode()這個方法也是從object類中繼承過來的,在object類中定義如下: 

       public native int hashCode(); 

      說明是一個本地方法,它的實現是根據本地機器相關的。再看它比較“官方”的詳細說明:hashCode()返回該對象的哈希碼值,該值通常是一個由該對象的內部地址轉換而來的整數,它的實現主要是爲了提高哈希表(例如java.util.Hashtable提供的哈希表)的性能。

      你可以對它的這樣“官方式”的定義漠視,但以下這一點你必須銘記:在每個重寫了equals方法的類中,你必須也要重寫hashCode方法。如果不這樣做的話,就會違反Object.hashCode的通用約定,從而導致該類無法與所有基於散列值(hash)的集合類結合在一起正常運行。 

      hashCode()的返回值和equals()的關係如下:

      如果x.equals(y)返回“true”,那麼x和y的hashCode()必須相等。 

      如果x.equals(y)返回“false”,那麼x和y的hashCode()有可能相等,也有可能不等。

說了這麼多,他們之間的具體關係還是看個例子好,以下是51px中吳老師的一個例子。

  1. public class TestEquals {  
  2.     public static void main(String args[]) {  
  3.         Student s1 = new Student("張一"6);  
  4.         Student s2 = new Student("張一"6);  
  5.   
  6.         if (s1.equals(s2)) {  
  7.             System.out.println("相同  s1的代碼:" + s1.hashCode() + "  s2的代碼:"  
  8.                     + s2.hashCode());  
  9.         } else {  
  10.             System.out.println("不相同");  
  11.         }  
  12.     }  
  13. }  
  14.   
  15. class Student {  
  16.     private int age;  
  17.     private String name;  
  18.       
  19.     public Student() {  
  20.     }  
  21.   
  22.     public Student(String name, int age) {  
  23.         this.age = age;  
  24.         this.name = name;  
  25.     }  
  26.   
  27.     public int getAge() {  
  28.         return age;  
  29.     }  
  30.   
  31.     public void setAge(int age) {  
  32.         this.age = age;  
  33.     }  
  34.   
  35.     public String getName() {  
  36.         return name;  
  37.     }  
  38.   
  39.     public void setName(String name) {  
  40.         this.name = name;  
  41.     }  
  42.   
  43.     public int hashCode() {  
  44.         return (this.name.hashCode() + this.age) * 31;  
  45.     }  
  46.   
  47.     public boolean equals(Object obj) {  
  48.         boolean result = false;  
  49.         if (obj == null) {  
  50.             result = false;  
  51.         }  
  52.         if (this == obj) {  
  53.             result = true;  
  54.         }  
  55.   
  56.         if (obj instanceof Student) {  
  57.             Student stu = (Student) obj;  
  58.             if (stu.getName().equals(this.name) && stu.getAge() == (this.age)) {  
  59.                 result = true;  
  60.             }  
  61.   
  62.         } else {  
  63.             result = false;  
  64.         }  
  65.         return result;  
  66.     }  
  67. }  
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章