Java中equals()與hashCode()的原理與設計

1.何時需要重寫equals()

當一個類有自己特有的“邏輯相等”概念(不同於對象身份的概念)。

2.爲什麼改寫equals()的時候,總是要改寫hashCode()

兩個原則:
hashCode()的返回值和equals()的關係如下:
  • 如果x.equals(y)返回“true”,那麼x和y的hashCode()必須相等。
  • 如果x.equals(y)返回“false”,那麼x和y的hashCode()有可能相等,也有可能不等。
簡單的說,“相等的對象必須具有相等的散列碼”。

3.什麼是equals()與如何設計equals()

它是對象內容的比較。涵蓋內容比對象參閱值比較更豐富。什麼是對象參閱值比較:就是兩個對象的參閱變量的值的比較。值是一個數字,通過數字來鑑別不同對象的代號,這種默認的比較方式,在object對象中已有設計實現。
而對象內容的比較纔是設計equals()的真正目的。

參考《effective java》上equals的幾個特性
  • 對稱性:如果x.equals(y)返回是“true”,那麼y.equals(x)也應該返回是“true”。
  • 反射性:x.equals(x)必須返回是“true”。
  • 類推性:如果x.equals(y)返回是“true”,而且y.equals(z)返回是“true”,那麼z.equals(x)也應該返回是“true”。
  • 還有一致性:如果x.equals(y)返回是“true”,只要x和y內容一直不變,不管你重複x.equals(y)多少次,返回都是“true”。
  • 任何情況下,x.equals(null),永遠返回是“false”;x.equals(和x不同類型的對象)永遠返回是“false”。

設計步驟:
[1]使用instanceof操作符檢查“實參是否爲正確的類型”。
[2]對於類中的每一個“關鍵域”,檢查實參中的域與當前對象中對應的域值。
[2.1]對於非floatdouble類型的原語類型域,使用==比較;
[2.2]對於對象引用域,遞歸調用equals方法;
[2.3]對於float域,使用Float.floatToIntBits(afloat)轉換爲int,再使用==比較;
[2.4]對於double域,使用Double.doubleToLongBits(adouble) 轉換爲int,再使用==比較;
[2.5]對於數組域,調用Arrays.equals方法。

4.什麼是hashcode()與如何設計hashCode()

這 個函數返回的就是一個用來進行哈希操作的整型代號,請不要把這個代號和前面所說的參閱變量所代表的代號弄混了。後者不僅僅是個代號還具有在內存中才查找對 象的位置的功能。hashCode()所返回的值是用來分類對象在一些特定的收集對象中的位置。
具體如HashMap內怎樣利用hashCode等詳細內容,請查閱http://blog.csdn.net/a511596982/article/details/8138893

設計步驟:
[1]把某個非零常數值,例如17,保存在int變量result中;
[2]對於對象中每一個關鍵域f(指equals方法中考慮的每一個域):
[2.1]boolean型,計算(f ? 0 : 1);
[2.2]byte,char,short型,計算(int);
[2.3]long型,計算(int) (f ^ (f>>>32));
[2.4]float型,計算Float.floatToIntBits(afloat);
[2.5]double型,計算Double.doubleToLongBits(adouble)得到一個long,再執行[2.3];
[2.6]對象引用,遞歸調用它的hashCode方法;
[2.7]數組域,對其中每個元素調用它的hashCode方法。
[3]將上面計算得到的散列碼保存到int變量c,然後執行 result=37*result+c;
[4]返回result

5.符合上面的原則的equals與hashcode的示例代碼
package com.zj.unit;
import java.util.Arrays;
 
public class Unit {
    private short ashort;
    private char achar;
    private byte abyte;
    private boolean abool;
    private long along;
    private float afloat;
    private double adouble;
    private Unit aObject;
    private int[] ints;
    private Unit[] units;
 
    public boolean equals(Object o) {
       if (!(o instanceof Unit))
           return false;
       Unit unit = (Unit) o;
       return unit.ashort == ashort
              && unit.achar == achar
              && unit.abyte == abyte
              && unit.abool == abool
              && unit.along == along
              && Float.floatToIntBits(unit.afloat) == Float
                     .floatToIntBits(afloat)
              && Double.doubleToLongBits(unit.adouble) == Double
                     .doubleToLongBits(adouble)
              && unit.aObject.equals(aObject)
&& equalsInts(unit.ints)
              && equalsUnits(unit.units);
    }
 
    private boolean equalsInts(int[] aints) {
       return Arrays.equals(ints, aints);
    }
 
    private boolean equalsUnits(Unit[] aUnits) {
       return Arrays.equals(units, aUnits);
    }
 
    public int hashCode() {
       int result = 17;
       result = 37 * result + (int) ashort;
       result = 37 * result + (int) achar;
       result = 37 * result + (int) abyte;
       result = 37 * result + (abool ? 0 : 1);
       result = 37 * result + (int) (along ^ (along >>> 32));
       result = 37 * result + Float.floatToIntBits(afloat);
       long tolong = Double.doubleToLongBits(adouble);
       result = 37 * result + (int) (tolong ^ (tolong >>> 32));
       result = 37 * result + aObject.hashCode();
       result = 37 * result + intsHashCode(ints);
       result = 37 * result + unitsHashCode(units);
       return result;
    }
 
    private int intsHashCode(int[] aints) {
       int result = 17;
       for (int i = 0; i < aints.length; i++)
           result = 37 * result + aints[i];
       return result;
    }
 
    private int unitsHashCode(Unit[] aUnits) {
       int result = 17;
       for (int i = 0; i < aUnits.length; i++)
           result = 37 * result + aUnits[i].hashCode();
       return result;
    }
}




發佈了46 篇原創文章 · 獲贊 31 · 訪問量 42萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章