天天看點

關于equals,hashCode的幾點筆記

equals方法

public boolean equals(Object obj)

訓示其他某個對象是否與此對象“相等”。

equals 方法在非空對象引用上實作相等關系:

  1. 自反性:對于任何非空引用值 x,x.equals(x) 都應傳回 true。
  2. 對稱性:對于任何非空引用值 x 和 y,當且僅當 y.equals(x) 傳回 true 時,x.equals(y) 才應傳回 true。
  3. 傳遞性:對于任何非空引用值 x、y 和 z,如果 x.equals(y) 傳回 true,并且 y.equals(z) 傳回 true,那麼 x.equals(z) 應傳回 true。
  4. 一緻性:對于任何非空引用值 x 和 y,多次調用 x.equals(y) 始終傳回 true 或始終傳回 false,前提是對象上 equals 比較中所用的資訊沒有被修改。
  5. 對于任何非空引用值 x,x.equals(null) 都應傳回 false。Object 類的 equals 方法實作對象上差别可能性最大的相等關系;即,對于任何非空引用值 x 和 y,當且僅當 x 和 y 引用同一個對象時,此方法才傳回 true(x == y 具有值 true)。

注意:當此方法被重寫時,通常有必要重寫 hashCode 方法,以維護 hashCode 方法的正常協定,該協定聲明相等對象必須具有相等的哈希碼。

參數:

obj - 要與之比較的引用對象。

傳回:

如果此對象與 obj 參數相同,則傳回 true;否則傳回 false。

實作高品質equals方法的訣竅

  1. 使用==操作符檢查“參數是否為這個對象的引用”。
  2. 使用instanceof操作符檢查“參數是否為正确的類型”。
  3. 把參數轉換為正确的類型。
  4. 對于該類中的每個“關鍵(significant)”域,檢查參數中的域是否與該對象中對應的域想比對。
  5. 當你編寫完成了equals方法之後,應該問自己三個問題:它是否是對稱的、傳遞的、一緻的?

一些告誡

  • 覆寫equals時總要覆寫hashCode。
  • 不要企圖讓equals方法過于智能。
  • 不要将equals聲明中的Object對象替換為其他的類型。

hashCode方法

public int hashCode()

傳回該對象的哈希碼值。支援此方法是為了提高哈希表(例如 java.util.Hashtable 提供的哈希表)的性能。

hashCode 的正常協定是:

在 Java 應用程式執行期間,在對同一對象多次調用 hashCode 方法時,必須一緻地傳回相同的整數,前提是将對象進行 equals 比較時所用的資訊沒有被修改。從某一應用程式的一次執行到同一應用程式的另一次執行,該整數無需保持一緻。

如果根據 equals(Object) 方法,兩個對象是相等的,那麼對這兩個對象中的每個對象調用 hashCode 方法都必須生成相同的整數結果。

如果根據 equals(java.lang.Object) 方法,兩個對象不相等,那麼對這兩個對象中的任一對象上調用 hashCode 方法不 要求一定生成不同的整數結果。但是,程式員應該意識到,為不相等的對象生成不同整數結果可以提高哈希表的性能。

實際上,由 Object 類定義的 hashCode 方法确實會針對不同的對象傳回不同的整數。(這一般是通過将該對象的内部位址轉換成一個整數來實作的,但是 JavaTM 程式設計語言不需要這種實作技巧。)

傳回:

此對象的一個哈希碼值。

幾點注意

  • 要想使hashCode()實用,它必須速度快,并且必須有意義。也就是說,它必須基于對象的内容生成散列碼。散列碼不必是獨一無二的(應該關注生成速度,而不是唯一性),但是通過hashCode()和equals(),必須能夠完全确定對象的身份。
  • 散清單的生成範圍并不重要,隻要是int就好
  • 好的hashCode()應該生成均勻分布的散列碼。如果散列碼都集中在一塊,那麼hashMap後者hashSet在某些區域的負載會很重,這樣就不如分布均勻的散列函數快。

如何生成一份像樣的hashCode():

  1. 給int變量result賦予某個非零常量
  2. 為對象每個有意義的域f(即每個可以做equals操作的域)計算出一個int散列碼c
  3. 合并計算得到的散列碼 result= 31*result+c;
  4. 傳回result
  5. 檢查hashCode()最後生成的結果,確定相同的對象有相同的散列碼