1. 程式人生 > >3. 你重寫過hashcode和equals麼,要注意什麼?

3. 你重寫過hashcode和equals麼,要注意什麼?

SUN官方的文件中規定"如果重定義equals方法,就必須重定義hashCode方法,以便使用者可以將物件插入到雜湊(雜湊)表中" 

那麼 SUN 公司是出於什麼考慮做了這個規定呢? 

在集合框架中的HashSetHashTableHashMap都使用雜湊表的形式儲存資料,而hashCode計算出來的雜湊碼便是它們的身份證。雜湊碼的存在便可以: 

  1. 快速定位物件,提高雜湊表集合的效能。
  2. 只有當雜湊表中物件的索引即hashCode和物件的屬性即equals同時相等時,才能夠判斷兩個物件相等。
  3. 從上面可以看出,雜湊碼主要是為雜湊表服務的,其實如果不需要使用雜湊表,也可以不重寫hashCode
    。但是SUN公司應該是出於對程式擴充套件性的考慮(萬一以後需要將物件放入雜湊表集合中),才會規定重寫equals的同時需要重寫hashCode,以避免後續開發不必要的麻煩。
  4. hashCode方法可以這樣理解:它返回的就是根據物件的記憶體地址換算出的一個值。這樣一來,當集合要新增新的元素時,先呼叫這個元素的hashCode方法,就一下子能定位到它應該放置的物理位置上。如果這個位置上沒有元素,它就可以直接儲存在這個位置上,不用再進行任何比較了;如果這個位置上已經有元素了,就呼叫它的equals方法與新元素進行比較,相同的話就不存了,不相同就雜湊其它的地址。這樣一來實際呼叫equals方法的次數就大大降低了,幾乎只需要一兩次。

重寫equals時需要注意滿足java語言規範對於equals的要求:

Java語言規範要求equals需要具有如下的特性: 

  1. 自反性:對於任何非空引用 x,x.equals() 應該返回 true
  2. 對稱性:對於任何引用 x 和 y,當且僅當 y.equals(x) 返回 truex.equals(y) 也應該返回 true
  3. 傳遞性:對於任何引用 x、y 和 z,如果 x.equals(y)返回 truey.equals(z) 也應返回同樣的結果。
  4. 一致性:如果 x 和 y 引用的物件沒有發生變化,反覆呼叫 x.equals(y) 應該返回同樣的結果。
  5. 對於任意非空引用 x,x.equals(null)
     應該返回 false

重寫equals時,用eclipes生成的原始碼:

@Override
public int hashCode() {
	final int prime = 31;
	int result = 1;
	result = prime * result + age;
	result = prime * result + ((name == null) ? 0 : name.hashCode());
	return result;
}
@Override
public boolean equals(Object obj) {
	if (this == obj)
		return true;
	if (obj == null)
		return false;
	if (getClass() != obj.getClass())
		return false;
	Dog other = (Dog) obj;
	if (age != other.age)
		return false;
	if (name == null) {
		if (other.name != null)
			return false;
	} else if (!name.equals(other.name))
		return false;
	return true;
}
注意:1.equalshashCode的定義必須一致,兩個物件equalstrue,就必須有相同的hashCode。反之,如果兩個物件的hashcode相同,equals不一定相同。2.當重寫equals方法時,一定要同時把hashcode方法一併重寫,因為要保證在實現hash表的擴充套件性