1. 程式人生 > >對於自定義類,重寫equals方法和hashCode方法的技巧

對於自定義類,重寫equals方法和hashCode方法的技巧

參考:http://blog.csdn.net/fenglibing/article/details/8905007

對於自定義的類,如果要比較兩個物件是否相同,就需要重寫equals方法。舉一個例子進行說明:

先自定義一個類,包含兩個屬性:

class Person{
	private String name;
	int id;
	
	public Person(){
		
	}
	public Person(String name, int id){
		this.id = id;
		this.name = name;
	}
	public void setName(String name){
		this.name = name;
	}
	public void setId(int id){
		this.id = id;
	}
	public String getName(){
		return this.name;
	}
	public int getId(){
		return this.id;
	}
	@Override
	public boolean equals(Object obj) {
		// TODO Auto-generated method stub
		if(this == obj){
			return true;
		}
		if(obj == null){
			return false;
		}
		if(!(obj instanceof Person)){
			return false;
		}
		final Person person = (Person)obj;
		if(!this.getName().equals(person.getName())){
			return false;
		}
		if(this.getId() != person.getId()){
			return false;
		}
		return true;
		
	}
	
}
然後在主函式中進行測試:
public class EqualsDemo {
	public static void main(String[] args){
		Person p1 = new Person("jack", 18);
		Person p2 = new Person("rose", 17);
		Person p3 = new Person("jack", 18);
		if(p1.equals(p2)){
			System.out.println("p1.equals p2");
		}
		if(p1.equals(p3)){
			System.out.println("p1.equals p3");
		}
		
	}
重寫equals方法的時候,一般會重寫hashCode方法,hashCode方法的官方文件解釋如下:
<pre name="code" class="java">hashcode方法返回該物件的雜湊碼值。支援該方法是為雜湊表提供一些優點,例如,java.util.Hashtable 提供的雜湊表。   
  
hashCode 的常規協定是:   
在 Java 應用程式執行期間,在同一物件上多次呼叫 hashCode 方法時,必須一致地返回相同的整數,前提是物件上 equals 比較中所用的資訊沒有被修改。從某一應用程式的一次執行到同一應用程式的另一次執行,該整數無需保持一致。   
如果根據 equals(Object) 方法,兩個物件是相等的,那麼在兩個物件中的每個物件上呼叫 hashCode 方法都必須生成相同的整數結果。   
以下情況不 是必需的:如果根據 equals(java.lang.Object) 方法,兩個物件不相等,那麼在兩個物件中的任一物件上呼叫 hashCode 方法必定會生成不同的整數結果。但是,程式設計師應該知道,為不相等的物件生成不同整數結果可以提高雜湊表的效能。   
實際上,由 Object 類定義的 hashCode 方法確實會針對不同的物件返回不同的整數。(這一般是通過將該物件的內部地址轉換成一個整數來實現的,但是 JavaTM 程式語言不需要這種實現技巧。)   
  
當equals方法被重寫時,通常有必要重寫 hashCode 方法,以維護 hashCode 方法的常規協定,該協定宣告相等物件必須具有相等的雜湊碼。

以上這段官方文件的定義,我們可以抽出成以下幾個關鍵點:

1、hashCode的存在主要是用於查詢的快捷性,如Hashtable,HashMap等,hashCode是用來在雜湊儲存結構中確定物件的儲存地址的;

2、如果兩個物件相同,就是適用於equals(Java.lang.Object) 方法,那麼這兩個物件的hashCode一定要相同;

3、如果物件的equals方法被重寫,那麼物件的hashCode也儘量重寫,並且產生hashCode使用的物件,一定要和equals方法中使用的一致,否則就會違反上面提到的第2點;

4、兩個物件的hashCode相同,並不一定表示兩個物件就相同,也就是不一定適用於equals(java.lang.Object) 方法,只能夠說明這兩個物件在雜湊儲存結構中,如Hashtable,他們“存放在同一個籃子裡”


hashCodeshi 是用於查詢使用的,而equals用於比較兩個物件是否相同。
  1. 1.hashcode是用來查詢的,如果你學過資料結構就應該知道,在查詢和排序這一章有  
  2. 例如記憶體中有這樣的位置  
  3. 0  1  2  3  4  5  6  7    
  4. 而我有個類,這個類有個欄位叫ID,我要把這個類存放在以上8個位置之一,如果不用hashcode而任意存放,那麼當查詢時就需要到這八個位置裡挨個去找,或者用二分法一類的演算法。  
  5. 但如果用hashcode那就會使效率提高很多。  
  6. 我們這個類中有個欄位叫ID,那麼我們就定義我們的hashcode為ID%8,然後把我們的類存放在取得得餘數那個位置。比如我們的ID為9,9除8的餘數為1,那麼我們就把該類存在1這個位置,如果ID是13,求得的餘數是5,那麼我們就把該類放在5這個位置。這樣,以後在查詢該類時就可以通過ID除 8求餘數直接找到存放的位置了。  
  7. 2.但是如果兩個類有相同的hashcode怎麼辦那(我們假設上面的類的ID不是唯一的),例如9除以8和17除以8的餘數都是1,那麼這是不是合法的,回答是:可以這樣。那麼如何判斷呢?在這個時候就需要定義 equals了。  
  8. 也就是說,我們先通過 hashcode來判斷兩個類是否存放某個桶裡,但這個桶裡可能有很多類,那麼我們就需要再通過 equals 來在這個桶裡找到我們要的類。  
  9. 那麼。重寫了equals(),為什麼還要重寫hashCode()呢?  
  10. 想想,你要在一個桶裡找東西,你必須先要找到這個桶啊,你不通過重寫hashcode()來找到桶,光重寫equals()有什麼用啊  
http://blog.csdn.net/fenglibing/article/details/8905007

所以有必要重寫hashcode函式,如何重寫呢?1. 根據底層雜湊表的儲存方式,雜湊表會將具有相同雜湊值的元素依次順延。2. 如果hashCode值相同,HashSet在儲存的時候,equals方法就會起作用。可以將所有的物件返回相同的hash值,但是需要增加計算量,對於兩個完全不同的物件,可以讓他們的hashCode就不相同,通過hashCode直接判斷出結果,不再呼叫equals方法。

一般的重寫方法,是利用現有的類的equals方法,對類具有的屬性進行線性組合。本類中,hashCode方法可以寫為:

	public int hashCode() {
		// TODO Auto-generated method stub
		return this.name.hashCode() + id;
	}
如此,便可以產生較為高效的hashCode,減少計算量。