【Effective Java 10.1】覆蓋 equals 時請遵守通用約定
阿新 • • 發佈:2022-03-26
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 方法。例如 Interger
或 String
。有時甚至需要同時覆寫 hashCode
方法。但有一種值類不需要覆蓋 equals 方法,即例項受控 ”確保物件只存在一個“(如單例物件,列舉類)
3. 覆蓋 equals 方法時的約定
- 自反性(reflexive):對於任何非 null 的引用值。
x.equals(x)
始終為真 - 對稱性(symmetric):對於任何非 null 的引用值
x
,y
。當且僅當y.equals(x)
返回true
時,x.equals(y)
必須返回true
- 傳遞性(transitive):對於任何非 null 的引用值
x
,y
和z
。如果x.equals(y)
返回true
時,且y.equals(z)
也返回true
,則x.equals(z)
也必須返回true
- 一致性(consistent):對於任何非 null 的引用值
x
y
,只要equals
的比較操作在物件中所有的資訊沒有被修改,多次呼叫x.equals(y)
就會一致地返回true
,或者一致地返回false
- 對於任何非 null 的引用值
x
,x.equals(null)
必須返回false
如果違反了這些規定,就會發現程式將會表現得不正常,甚至崩潰,而且很難找到程式的 Bug 所在。