第8條:覆蓋equals時請遵照通用約定

一、equals方法

1.一、簡介

equals()方法,定義在Object類中,源碼以下:html

public boolean equals(Object obj) {
        return (this == obj);
    }

  也就是說,在Object類中,比較的是兩個對象的引用是否相同。
  當咱們建立一個新的類而沒有覆蓋equals方法時,調用equals方法即比較兩個對象的引用是否相同,此時與使用「==」比較是同樣的。java

1.二、equals與==

參考:淺談Java中的equals和==測試

  String類對equals方法進行了重寫,用來比較指向的字符串對象所存儲的字符串是否相等。其餘的一些類諸如Double,Date,Integer等,都對equals方法進行了重寫用來比較指向的對象所存儲的內容是否相等。flex

總結來講:ui

  • 對於==,若是做用於基本數據類型的變量,則直接比較其存儲的 「值」是否相等;若是做用於引用類型的變量,則比較的是所指向的對象的地址
  • 對於equals方法(注意:equals方法不能做用於基本數據類型的變量),若是沒有對equals方法進行重寫,則比較的是引用類型的變量所指向的對象的地址;諸如String、Date等類對equals方法進行了重寫的話,比較的是所指向的對象的內容。

二、不須要覆蓋equals方法

當有以下條件時,不須要覆蓋equals方法:this

  • 類的每一個實例本質上都是惟一的。
  • 不關心類是否提供了「邏輯相等(logical equality)」的測試功能。
  • 超類已經覆蓋了equals,從超類繼承過來的行爲對於子類也是適合的。
  • 類是私有的或是包級私有的,能夠肯定它的equals方法永遠不會被調用。

三、覆蓋equals方法

3.一、何時該覆蓋

  若是類具備本身特有的「邏輯相等」概念(不一樣於對象等同的概念),並且超類尚未覆蓋equals以實現指望的行爲,這時就須要覆蓋equals方法。
  這一般屬於「值類(value class)」的情形。值類僅僅是一個表示值的類,例如Ingeter或Date,在利用equals方法來比較值對象的引用時,但願知道它們在邏輯上是否相等,而不是想了解它們是否指向同一個對象。.net

3.二、覆蓋時遵照約定

等價關係(equivalence relation):code

  • 自反性(reflexive):對於任何非null的引用值x,x.equals(x)必須返回true。
  • 對稱性(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)總會一致地返回相同的結果。
  • 非空性(Non-nullity):對於任何非null的引用值x,x.equals(null)必須返回false。

四、實現高質量equals

  1. 使用「==」操做符檢查「參數是否爲這個對象的引用」。
  2. 使用instanceof操做符檢查「參數是否爲正確的類型」。
  3. 把參數轉換成正確的類型。
  4. 對於該類中的每一個「關鍵(significant)」域,檢查參數中的域是否與該對象中對應的域相匹配。
  5. 當你編寫完成了equals方法以後,應該問本身三個問題:它是否對稱的、傳遞的、一致的?

五、告誡

  • 覆蓋equals時總要覆蓋hashCode
  • 不要企圖讓equals方法過於智能
  • 不要將equals聲明中的Object對象替換爲其餘的類型。

六、參考

相關文章
相關標籤/搜索