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

覆蓋equals有時看起來很簡單,可是許多覆蓋方式會產生錯誤。通常來講須要知足如下條件:
java

1:類的每一個實例本質上都是惟一的。eclipse

2:不關心類是否提供了「邏輯相等(logical equality)」的測試功能。 ide

3:超類已經覆蓋了equals,從超類繼承過來的行爲對於子類也是合適的。 測試

4:類是私有的或是包級私有的,能夠肯定他的equals方法永遠不會被調用。this

首先看個例子spa

public final class CaseInsensitiveString {
   private final String s;

   public CaseInsensitiveString(String s) {
      if (s == null)
         throw new NullPointerException();
      this.s = s;
   }

   // Broken - violates symmetry!
   @Override
   public boolean equals(Object o) {
      if (o instanceof CaseInsensitiveString)
         return s.equalsIgnoreCase(((CaseInsensitiveString) o).s);
      if (o instanceof String) // One-way interoperability!
         return s.equalsIgnoreCase((String) o);
      return false;
   }

   public static void main(String[] args) {
      CaseInsensitiveString cis = new CaseInsensitiveString("Polish");
      String s = "polish";
      System.out.println("cis.equals(s): "+cis.equals(s));
      System.out.println("s.equals(cis):"+s.equals(cis));
   }
該代碼運行結果:
cis.equals(s): true
s.equals(cis):false

這個類的equals意圖很好,它企圖與普通的字符串(String)進行互相操做,正如你們所料,cis.equals(s)返回true,由於cis是對象,調用的是CaseInsensitiveString類中的equals。而s.equals(cis)返回false。是由於s字符串,默認它的equals調用的是String類中的equals方法,因此返回false。code

實現高質量equals方法的訣竅: 對象

一、使用==操做符檢查「參數是否爲這個對象的引用」。 繼承

二、使用instanceof操做符檢查「參數是否爲正確的類型」。 ip

三、把參數轉換成正確的類型。 

四、對於該類的每一個「關鍵(significant)」域,檢查參數中的域是否與該對象中對應的域相匹配。 

這點myeclipse自動生成的並不徹底完美,myeclipse生成以下: 

else if (!name.equals(other.name)) 

return false; 

可是,這條是要求你改爲: 

else if (name != other.name && !name.equals(other.name)) 

return false; 

五、當你編寫完成了equals方法以後,應該會問本身三個問題:他是否的對稱的、傳遞的、一致的。 

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


儘可能不要省略@Override。 

相關文章
相關標籤/搜索