1. 程式人生 > 其它 >【Effective Java 10.1】覆蓋 equals 時請遵守通用約定

【Effective Java 10.1】覆蓋 equals 時請遵守通用約定

1. 不需要覆蓋 equals 方法的情況

覆蓋 equals 方法看起來很簡單,但是有許多覆蓋方式會導致錯誤,並且後果非常嚴重。最容易避免這類問題的辦法就是不覆蓋 equals 方法,在這種情況下,類的每個例項都只與其自身相等。以下情況不需要覆蓋 equals 方法

  • 類的每個例項本質上都是唯一的:對於代表 “活動實體” 而非 “值” 類,例如 Thread
  • 類沒有必要提供 ”邏輯相等“ 的測試功能:例如,java.util.regex.Pattern 可以覆蓋 equals,以檢查兩個 Pattern 例項是否代表同一個正確表示式,但是設計者並不認為客戶需要或者期望這樣的功能。在這類情況之下,從 Object
    繼承得到了 equals 實現已經足夠了
  • 超類已經覆蓋了 equals,超類的行為對於這個類也是合適的。例如,大多數的 Set 實現都從 AbstractSet 繼承 equals 實現,List 實現從 AbstractList 繼承 equals 實現,Map 實現從 AbstractMap 繼承 equals 實現。
  • 類是私有的,或者是包級私有,可以確定它的 equals 方法永遠不會被呼叫

2. 需要覆蓋 equals 方法的情況

對於大部分 ”值“ 類物件都需要覆蓋 equals 方法。例如 IntergerString。有時甚至需要同時覆寫 hashCode 方法。但有一種值類不需要覆蓋 equals 方法,即例項受控 ”確保物件只存在一個“(如單例物件,列舉類)

3. 覆蓋 equals 方法時的約定

  • 自反性(reflexive):對於任何非 null 的引用值。x.equals(x) 始終為真
  • 對稱性(symmetric):對於任何非 null 的引用值 xy。當且僅當 y.equals(x) 返回 true 時,x.equals(y) 必須返回 true
  • 傳遞性(transitive):對於任何非 null 的引用值 xyz。如果 x.equals(y) 返回 true 時,且 y.equals(z) 也返回true,則x.equals(z)也必須返回 true
  • 一致性(consistent):對於任何非 null 的引用值 x
    y,只要 equals 的比較操作在物件中所有的資訊沒有被修改,多次呼叫 x.equals(y) 就會一致地返回 true,或者一致地返回 false
  • 對於任何非 null 的引用值 xx.equals(null) 必須返回 false

如果違反了這些規定,就會發現程式將會表現得不正常,甚至崩潰,而且很難找到程式的 Bug 所在。