利用Commons Lang庫改寫equals與hashCode方法

關於如何改變 Java類中的equals與hashCode方法,Effective Java一書中提供了一個行之有效的方法。改寫equals方法的步驟爲:
  1. 使 用==操作符檢查“實參是否爲指向對象的一個引用”。
  2. 使用instanceof操作符檢查“實參是否爲正確的類型”。
  3. 把 實參轉換到正確的類型。
  4. 對於該類中每一個“關鍵”域,檢查實參中的域與當前對象中對應的域值是否匹配。
其中最後一步書中的描述爲:
  • 對於既不是float也不是double類型的簡單類型域,可以使用==操作符進行比較;
  • 對 於對象引用域,可以遞歸地調用equals方法;
  • 對於float域,先使用Float.floatToIntBits轉換成int類型 的值,然後使用==操作符比較int類型的值;
  • 對於double域,先使用Double.doubleToLongBits轉換成 long類型的值,然後使用==操作符比較long類型的值;
  • 對於數組域,把以上這些指導原則應用到每個元素上。
有些對象引用域包含null是合法的,所以爲了避免可能導致NullPointerException 異常,使用下面的習慣用法來比較這樣的域:
(field == o.field || (field != null && field.equals(o.field))
改寫equals時總是要改寫hashCode,改寫hashCode方法的步驟爲:
  1. 把某個非零常數值比如說17, 保存在一個叫result的int類型的變量中。
  2. 對於對象中每一個關鍵域f(指equals方法中考慮的每一個域),完成以下步驟:
    1. 爲該域計算int類型的散列碼c:
      1. 如果該域是boolean類型,則計算(f ? 0 : 1)。
      2. 如果該域是byte、 char、short或者int類型,則計算(int)f。
      3. 如果該域是long類型,則計算(int)(f ^ (f >>> 32))。
      4. 如果該域是float類型,則計算Float.floatToIntBits(f)。
      5. 如 果該域是double類型,則計算Double.doubleToLongBits(f)得到一個long類型的值,然後按照步驟2.1.3,對該 long型值計算散列值。
      6. 如果該域是一個對象引用,並且該類的equals方法通過遞歸調用equals的方式來比較這個域,則同樣對 這個域遞歸調用hashCode。如果這個域的值爲null,則返回0。
      7. 如果該域是一個數組,則把每一個元素當做單獨的域來處理。
    2. 按照下面的公式,把步驟a中計算得到的散列碼c組合到result中:result = 37 * result + c
  3. 返回result。
上述方案中關於“關鍵”域的計算過程是比較複雜的,看一看下面這個簡單類Point實現的equals與 hashCode方法:

如果“關鍵”域數量較多,實現上難免出現錯誤。Commons Lang庫爲我們提供了兩個工具類用於簡化equals方法的第4步及hashCode方法的第2步,它們分別爲EqualsBuilder與HashCodeBuilder類。如上例的Commons Lang庫版本:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章