1. 程式人生 > >Java中重寫Object類的equals方法和Hashcode方法的注意事項

Java中重寫Object類的equals方法和Hashcode方法的注意事項

在重寫任何類的equals方法是必須遵循以下幾點:

1、對稱性:如果x.equals(y)返回是“true”,那麼y.equals(x)也應該返回是“true”。

2、反射性:x.equals(x)必須返回是“true”。

3、類推性:如果x.equals(y)返回是“true”,而且y.equals(z)返回是“true”,那麼z.equals(x)也應該返回是“true”。

4、還有一致性:如果x.equals(y)返回是“true”,只要x和y內容一直不變,不管你重複x.equals(y)多少次,返回都是“true”。

5、任何情況下,x.equals(null),永遠返回是“false”;

在重寫任何類得hashcode方法是必須遵循以下幾點:

1、在Java應用的同一次執行過程中,同一物件被多次呼叫,則他們的hashcode值必然相同。而對於同一個應用的兩次不同的呼叫,它們的Hashcode值可以相同,也有可能不同。

2、對於兩個物件來說,如果他們的equals方法比較返回true,那麼這兩個物件的hashcode必然相同。這也解釋了為什麼String類中,如果兩個物件的equals方法相同,則他們的hashcode值一定相同。

3、對於兩個物件來說,如果使用equals方法返回為false,則他們的hashcode的值有可能相等也可能不等,(如果不同會提高效能,因為在集合中類判斷兩個物件是否相等,如果其hashcode不等就直接不用判斷equals方法了)

4、對於Object物件來說,不同的Object物件的hashcode是不同的,它們返回的是物件的地址,equals返回的也是物件的地址。所以在自己定義的類中如果要新增到集合物件中,最好是要重寫hashcode和equals方法,不然會自動繼承自Object類中的兩個方法根據物件地址來判斷。在重寫自己定義的類時,通常是在類中的根據某個值如name.hashcode();來進行判斷。

以HashSet 為例,

當我們使用HashSet時,hashCode()方法就會被得到呼叫,判斷已經儲存在集合中的物件的hashCode值是否與所增加

物件的hashCode值一致,如果“不一致”則直接加進去(不用比較equals()提高效率),如果一致,則進行equals方法的比較,如果返回true,表明 集合裡面已經有這個物件,不能新增進去了。如果是false表是集合裡面沒有這個物件,則可以加進去。所以我們在重寫hashcode()或者equals() 方法的任何一個方法時,必須重寫另外一個。 自己手工寫了一個類來重寫這兩個方法:

[java] view plaincopyprint?
  1. /**
  2. *
  3. * People 手工重寫hashcode方法和equals方法 根據name來判斷 兩個物件是否相等。 2011-7-12 上午09:09:56
  4. *
  5. * @version 1.0.0
  6. *
  7. */
  8. class People {
  9. private String name;
  10. public People(String name) {
  11. this.name = name;
  12. }
  13. @Override
  14. publicboolean equals(Object obj) {
  15. // TODO Auto-generated method stub
  16. //如果是自己
  17. if(this==obj){
  18. returntrue ;
  19. }
  20. //如果是空
  21. if(obj==null ){
  22. returnfalse;
  23. }
  24. //比較兩個People的名字是否相同
  25. if(obj!=null && obj instanceof People){
  26. if(((People)obj).name.equals(this.name))
  27. returntrue ;
  28. }
  29. returnfalse;
  30. }
  31. @Override
  32. publicint hashCode() {
  33. // TODO Auto-generated method stub
  34. // String的hashcode本來就是用來比較兩個字元是否相等
  35. return name.hashCode();
  36. }
  37. }
/**
 * 
 * People 手工重寫hashcode方法和equals方法 根據name來判斷 兩個物件是否相等。 2011-7-12 上午09:09:56
 * 
 * @version 1.0.0
 * 
 */
class People {
	private String name;

	public People(String name) {
		this.name = name;
	}

	@Override
	public boolean equals(Object obj) {

		// TODO Auto-generated method stub
		//如果是自己
		if(this==obj){
			return true ;

		}
		//如果是空
		if(obj==null ){
			return false;
		}
		//比較兩個People的名字是否相同
		if(obj!=null && obj instanceof People){
			if(((People)obj).name.equals(this.name))
				return  true ;

		}
		return false;

	}

	@Override
	public int hashCode() {

		// TODO Auto-generated method stub
		// String的hashcode本來就是用來比較兩個字元是否相等
		return name.hashCode();

	}

}

其他相關問題:

那麼在String中的hashcode是怎麼定義的呢?在String的API中我們可以看到這樣一個公式: s[0]*31^(n-1) + s[1]*31^(n-2) + … + s[n-1] 使用int 演算法,這裡s[i] 是字串的第i 個字元,n 是字串的長度,^ 表示求冪。(空字串的雜湊碼為0。)這說明String 中的hashcode 返回的並不是在記憶體中的地址,如果兩個字串的內容相同(equals為true),則其hashcode值必然就相同,equal為true。同理經過傻蛋測試在Integer類中和String類似,hashcode方法和equals方法也是判斷其包裹的原始值的內容是否相同。

總結:在Java中,String 、Math、還有Integer、Double。。。。等這些封裝類重寫了Object中的equals()方法,讓它不再比較其物件在記憶體中的地址,而是比較物件中實際包含的整數的值,即比較的是內容。再強調一次,Object的equals()方法比較的是地址值,所以Object equals相等時,其hashcode必然相等,因為都是物件的地址,所以自己定義的類如果要加入到集合類中一定要記得重寫這兩個方法。

在Eclipse中重寫hashcode和equals方法使相當方便的,只需要右鍵->source->Generate hashcode() and equals()便可以了。