爲什麼重寫equals 和hashCode方法,如何重寫

一.爲什麼要重寫

Java中的超類Object類中定義的equals()方法是用來比較兩個引用所指向的對象的內存地址是否一致

Object類中equals()方法的源碼

public boolean equals(Object obj) {

       return (this == obj);

}

********************************************************************

Object類中的hashCode()方法,用native關鍵字修飾,說明這個方法是個原生函數,也就說這個方法的實現不是用java語言實現的,是使用c/c++實現的,並且被編譯成了DLL,由java去調用,jdk源碼中不包含。對於不同的平臺它們是不同的,java在不同的操作系統中調用不同的native方法實現對操作系統的訪問,因爲java語言不能直接訪問操作系統底層,因爲它沒有指針。

這種方法調用的過程:

1、在java中申明native方法,然後編譯

2、用javah產生一個  .h  文件

3、寫一個 .cpp文件實現native導出方法,其中需要包含第二步產生的.h文件(其中又包含了jdk帶的jni.h文件);

4、將.cpp文件編譯成動態鏈接庫文件

5、在java中用System.loadLibrary()文件加載第四步產生的動態鏈接庫文件,然後這個navite方法就可被訪問了

Java的API文檔對hashCode()方法做了詳細的說明,這也是我們重寫hashCode()方法時的原則【Object類】

重點要注意的是:

a.  在java應用程序運行時,無論何時多次調用同一個對象時的hsahCode()方法,這個對象的hashCode()方法的返回值必須是相同的一個int值

b.  如果兩個對象equals()返回值爲true,則他們的hashCode()也必須返回相同的int值

c.  如果兩個對象equals()返回值爲false,則他們的hashCode()返回值也必須不同

public native int hashCode();

 

現在到了說正題了,爲什麼要重寫

我們在定義類時,我們經常會希望兩個不同對象的某些屬性值相同時就認爲他們相同,所以我們要重寫equals()方法,按照原則,我們重寫了equals()方法,也要重寫hashCode()方法,要保證上面所述的b,c原則;所以java中的很多類都重寫了這兩個方法,例如String類,包裝類

 

什麼情況下需要重寫hashCode()方法和equals()方法:

當我們自定義的一個類,想要把它的實例保存在集合中時,我們就需要重寫這兩個方法;集合(Collection)有兩個類,一個是List,一個是Set

List:集合中的元素是有序的,可以重複的

Set:無序,不可重複的

以HashSet來說明:

HashSet存放元素時,根據元素的hashCode值快速找到要存儲的位置,如果這個位置有元素,兩個對象通過equals()比較,如果返回值爲true,則不放入;如果返回值爲false,則這個時候會以鏈表的形式在同一個位置上存放兩個元素,這會使得HashSet的性能降低,因爲不能快速定位了。還有一種情況就是兩個對象的hashCode()返回值不同,但是equals()返回true,這個時候HashSet會把這兩個對象都存進去,這就和Set集合不重複的規則相悖了;所以,我們重寫了equals()方法時,要按照b,c規則重寫hashCode()方法!

二.如何重寫

比較兩個Java對象時, 我們需要覆蓋equals和  hashCode
[java] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. public class User{      
  2.     private String name;  
  3.     private int age;  
  4.     private String passport;  
  5.   
  6.     //getters and setters, constructor  
  7. }  

在比較結果時:
[java] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. User user1 = new User("mkyong"35"111222333");  
  2. User user2 = new User("mkyong"35"111222333");  
  3.   
  4. System.out.println(user1.equals(user2)); // false  

下面我們將介紹幾種常用方法:

 1.經典方式

這種17和31散列碼的想法來自經典的Java書籍——《Effective Java》第九條。下面我們來看看是如何實現的...
[java] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. public class User {  
  2.     private String name;  
  3.     private int age;  
  4.     private String passport;  
  5.     //getters and setters, constructor  
  6.     @Override  
  7.     public boolean equals(Object o) {  
  8.         if (o == thisreturn true;  
  9.         if (!(o instanceof User)) {  
  10.             return false;  
  11.         }  
  12.         User user = (User) o;  
  13.         return user.name.equals(name) &&  
  14.                 user.age == age &&  
  15.                 user.passport.equals(passport);  
  16.     }  
  17.     //Idea from effective Java : Item 9  
  18.     @Override  
  19.     public int hashCode() {  
  20.         int result = 17;  
  21.         result = 31 * result + name.hashCode();  
  22.         result = 31 * result + age;  
  23.         result = 31 * result + passport.hashCode();  
  24.         return result;  
  25.     }  
  26. }  

2.JDK 7

對於JDK7及更新版本,你可以是使用java.util.Objects 來重寫 equals 和 hashCode 方法,代碼如下

[java] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. import java.util.Objects;  
  2.   
  3. public class User {  
  4.     private String name;  
  5.     private int age;  
  6.     private String passport;  
  7.   
  8.     //getters and setters, constructor  
  9.   
  10.     @Override  
  11.     public boolean equals(Object o) {  
  12.         if (o == thisreturn true;  
  13.         if (!(o instanceof User)) {  
  14.             return false;  
  15.         }  
  16.         User user = (User) o;  
  17.         return age == user.age &&  
  18.                 Objects.equals(name, user.name) &&  
  19.                 Objects.equals(passport, user.passport);  
  20.     }  
  21.   
  22.     @Override  
  23.     public int hashCode() {  
  24.         return Objects.hash(name, age, passport);  
  25.     }  
  26.   
  27. }  

3.Apache Commons Lang

或者,您可以使用Apache Commons LangEqualsBuilder HashCodeBuilder 方法。代碼如下
[java] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. import org.apache.commons.lang3.builder;  
  2.   
  3. public class User {  
  4.     private String name;  
  5.     private int age;  
  6.     private String passport;  
  7.     //getters and setters, constructor  
  8.   
  9.      @Override  
  10.     public boolean equals(Object o) {  
  11.   
  12.         if (o == thisreturn true;  
  13.         if (!(o instanceof User)) {  
  14.             return false;  
  15.         }  
  16.         User user = (User) o;  
  17.   
  18.         return new EqualsBuilder()  
  19.                 .append(age, user.age)  
  20.                 .append(name, user.name)  
  21.                 .append(passport, user.passport)  
  22.                 .isEquals();  
  23.     }  
  24.     @Override  
  25.     public int hashCode() {  
  26.         return new HashCodeBuilder(1737)  
  27.                 .append(name)  
  28.                 .append(age)  
  29.                 .append(passport)  
  30.                 .toHashCode();  
  31.     }  
  32. }  

最後測試總結:

在使用上述三種任何一種方式都可以到如下結果:
[java] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. User user1 = new User("mkyong"35"111222333");  
  2. User user2 = new User("mkyong"35"111222333");  
  3. System.out.println(user1.equals(user2)); // true</span>  

其實後兩種都是對於17和31散列碼思想的封裝實現。具體請參考《Effective Java》第九條。

整理自:http://blog.csdn.net/jing_bufferfly/article/details/50868266

http://blog.csdn.net/zzg1229059735/article/details/51498310

發佈了5 篇原創文章 · 獲贊 3 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章