Effective Java Item 8 note

Obey the general contract when overriding equals

Arwii
mycodingjourney
3 min readMay 25, 2018

--

底下是可以不需要Override equals的條件,任一皆可:

  1. class的每個instance都是唯一的
  2. 不關心class是否提供logical equality的測試功能
  3. Super class已經Override equals,然後在子類也通用。
  4. Private class or private inner class,可以確定equals永遠不會被使用。

底下是需要Override equals的情形:

出現需要自己處理邏輯相等的定義,且super class也還沒有Override。Ex : value class。

Equals的通用約定:

要滿足equivalence relation:

  • Reflexive : non null x, x.equals(x) 必須是true

正常應該是不會有問題。

  • Symmetric:non null x,y , x.equals(y) 是true。那麼y.equals(x) 也要是true

書本上的例子是Wrapper primitive class,然後多判斷了原本的primitive的條件,但是primitive type並不知道這個wrapper class是誰造成的。

  • Transitive:non null x,y,z , x.equals(y) 是true且y.equals(z)也是true。那麼y.equals(x) 也要是true

書本上的例子是,想像一下有個value component class,如果被extends之後,會需要怎麼處理這個equals

a. 使用parent的equals,那麼children的內容就不會被比較到了(X)

b. 如果override掉parent的equals,要嘛違反Symmetric,不然就是違反

Transitive

這是在面對oo上面關於等價關係的一個基本問題,我們沒辦法在擴展可實例化的class的同時,既增加新的值同時又保留equals。

而且當你使用到Collection的class,裡面的contains的method用的是equals去做存在的比較,所以這樣的處理也會造成錯誤的結果。

解法:

可以使用compose取代extends,讓看起來比較像has a的屬性自己成立一個class,而不是硬要使用is a,而去破壞了原本class的Transitive

P.S. 不要混用java.sql.Timestamp 跟java.util.Date,java.sql.Timestamp的equals破壞了對稱性。

  • Consistent:non null x,y, 只要在equals的比較操作中所使用到的值沒有被修改,多次使用x.equals(y)應該都是返回一樣的結果

不要讓equals依賴於不可靠的資源,像是書本上提到的java.net.URL的equals是依賴URL中主機的ip,ip是可能隨著時間變動不同的。

  • Non-nullity

對於non null x, x.equals(null)必須是false

可以利用if (!(o instances Type) ) return false;來判斷是不是對的class以及object是不是null

記得要寫unit test來測試你有override equals的class。

記得override equals也同時要override hashCode(item 9)

記得不要讓equals過於聰明

記得不要這樣寫

public boolean equals(MyClass o),這樣不是Override是overload

--

--

Arwii
mycodingjourney

Try not to become a man of success, but rather try to become a man of value — A. Einstein