如何正確的覆蓋equals和hashCode

1、Object全部的非final方法

  1. public boolean equals(Object obj)
  2. public native int hashCode()
  3. public String toString()
  4. protected native Object clone() throws CloneNotSupportedException
  5. protected void finalize() throws Throwable { }

類的方法前加final關鍵字,說明該方法不能被該類的子類重寫。ide

2、equals方法和hashCode方法

一、何時須要覆蓋equals方法

若是類具備本身特有的「邏輯相等」概念(不一樣於對象等同的概念),並且超類尚未覆蓋equals以實現指望的行爲,這時候咱們就須要覆蓋equals方法。this

二、如何正確的覆蓋equals方法

equals方法實現了等價關係:自反性,對稱性,傳遞性,一致性,非空性(x.equals(null)返回爲falsespa

  • 使用==操做符檢查「參數是否爲這個對象的引用」,若是是,則返回true。
  • 使用instanceof操做符檢查「參數是否爲正確的類型」,若是不是,則返回false。
  • 把參數轉換成正確的類型。
  • 對於該類中的每一個「關鍵」閾,檢查參數中的閾是否與該對象中對應的閾相匹配。
class Student{
    
    private String name;
    private int age;
    private double height; 
    @Override
    public boolean equals(Object obj) {
        //使用==操做符檢查「參數是否爲這個對象的引用」
        if(this==obj)
            return true;
        //使用instanceof操做符檢查「參數是否爲正確的類型」
        if(!(obj instanceof Student))
            return false;
        //把參數轉換成正確的類型。
        Student student=(Student) obj;
        //對於該類中的每一個「關鍵」閾,檢查參數中的閾是否與該對象中對應的閾相匹配。
        return  this.name==student.name && this.age==student.age && this.height==student.height;
    }
}

一、編寫完成equals方法以後,應該問本身三個問題:它是否對稱的、傳遞的、一致的。code

二、不要將equals聲明中的Object對象替換爲其餘的類型對象

public boolean equals(Student obj)

這樣至關於重載了equals方法,而非是覆蓋。blog

三、覆蓋equals時總要覆蓋hashCode

HashCode有一條約定以下:遞歸

若是兩個對象根據equals(Object)方法比較是相等,那麼調用這兩個對象中任意一個對象的hashCode方法都必須產生一樣的整數結果。string

下面給出一種簡單的解決辦法:hash

  1. 把某個非零的常數值,好比說17,保存在一個名爲result的int類型的變量中。
  2. 對於對象每一個關鍵域f(指equals方法中涉及的每一個域),完成如下步驟:
    1. 若是該域是boolean類型,則計算(f ? 1 : 0)。
      private boolean flag=true;
      int boolTemp=flag?0:1;
    2. 若是該域是byte、char、short或者int類型,則計算(int)f。
    3. 若是該域是float類型,則計算Float.floatToIntBit(f)。
    4. 若是該域是long類型,則計算(int)(f ^ (f >>> 32))。
    5. 若是該域是double類型
      private double height; 
      long heightBits=Double.doubleToLongBits(height);
      int heightTemp=(int)(heightBits ^ (heightBits >>> 32));
    6. 若是該域是一個對象引用,而且該類的equals方法經過遞歸調用equals的方式來比較這個域,則一樣爲這個域遞歸調用hashCode。
      private String name;
      int stringTemp=this.name.hashCode();

完整的Student類:it

class Student{
    private String name;
    private int age;
    private double height; 
    @Override
    public boolean equals(Object obj) {
        //使用==操做符檢查「參數是否爲這個對象的引用」
        if(this==obj)
            return true;
        //使用instanceof操做符檢查「參數是否爲正確的類型」
        if(!(obj instanceof Student))
            return false;
        //把參數轉換成正確的類型。
        Student student=(Student) obj;
        //對於該類中的每一個「關鍵」閾,檢查參數中的閾是否與該對象中對應的閾相匹配。
        return  this.name==student.name && this.age==student.age && this.height==student.height;
    }
    
    @Override
    public int hashCode() {
        //初始化
        int result=17;
        //String類型
        result=this.name.hashCode()+result;
        //int類型
        result=this.age+result;
        //double類型
        long heightBits=Double.doubleToLongBits(height);
        int heightTemp=(int)(heightBits ^ (heightBits >>> 32));
        result=heightTemp+result;
        //返回
        return result;
    }
}
相關文章
相關標籤/搜索