亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

在繼承層次結構中實現健壯的 equals() 和 hashCode() 方法的正確方法是什么?

在繼承層次結構中實現健壯的 equals() 和 hashCode() 方法的正確方法是什么?

米琪卡哇伊 2022-01-19 17:09:13
我有以下抽象Person類:import java.util.Objects;public abstract class Person {    protected String name;    protected int id;    public Person(String name, int id) {        this.name = name;        this.id = id;    }    public abstract String description();    @Override    public boolean equals(Object obj) {        if(this == obj) return true;        if(!(obj instanceof Person)) return false;        return Objects.equals(this.name, ((Person) obj).name) &&                this.id == ((Person) obj).id;    }    @Override    public int hashCode() {        return Objects.hash(this.name, this.id);    }}現在我有一個Person名為的子類Employee:import java.time.LocalDate;import java.util.Objects;public class Employee extends Person {    private double salary;    private LocalDate hireDay;    public Employee(String name, int id, double salary, int year, int month, int day) {        super(name, id);        this.salary = salary;        this.hireDay = LocalDate.of(year, month, day);    }    @Override    public String description() {        return "Employee with a salary of " + this.salary;    }    @Override    public int hashCode() {        return super.hashCode() + Objects.hash(this.salary,this.hireDay);    }}要正確實現 equals 方法,它必須符合以下約定。自反式:x.equals(x) 始終為真對稱式:x.equals(y) 等價于 y.equals(x)傳遞式:x.equals(y) 和 y.equals(z) 蘊含 x.equals(z)是真的當我在子類內部調用超類的equals()方法時,我首先確保所有被比較的對象都是超類的子類。這個問題解決了比較混合類型的問題,并照顧了上面提到的合同。我不再需要使用以下 equals 實現:也就是說,我不再需要顯式檢查當前對象 ( ) 是否與使用運算符的超類中的方法this屬于同一類。objinstance of將該實現放在超類的equals運算符中是否更健壯,或者使用該getClass()方法在子類中使用更明確的測試以符合合同更好?就 hashCode() 方法而言,我對特定于子類的私有實例字段進行哈希處理,然后簡單地將其添加到超類中哈希方法的結果中。我找不到任何文檔來說明這是否是實現 hashCode() 函數的正確方法,或者在繼承層次結構中。我見過人們明確指定自己的哈希函數的代碼。如果我的問題過于籠統,我深表歉意,但我盡我所能地問他們,但不會太模棱兩可。編輯:我要求 Intellij 實現一個 equals 和 hashcode 方法,它決定使用我上面發布的最后一個實現。那么,在什么情況下我會instance of在超類中使用呢?當我在超類中實現最終的equals方法時會不會是這樣,例如僅根據用戶ID比較Person對象?
查看完整描述

3 回答

?
qq_花開花謝_0

TA貢獻1835條經驗 獲得超7個贊

以下是我在閱讀 Effective Java 2nd Edition 時的筆記:

Equals 必須遵守一般合同:

  • 反身的:對于non-null xx.equals(x) == true

  • 對稱:對于non-null x,yx.equals(y) <==> y.equals(x)

  • 傳遞:對于non-null x,y,zx.equals(y) and y.equals(z) ==> x.equals(z) == true

  • 一致:對于任何非空 x,y: if x.equals(y) == true,如果xy

  • 空:對于非空xx.equals(null) == false

高質量等于方法:

  1. 使用 == 檢查參數是否是對該對象的引用 ( x == x)

  2. 使用 instanceof 檢查參數是否是正確的類型(也檢查null

  3. 將參數轉換為正確的類型

  4. 對于類中的每個“重要”字段,檢查參數的該字段是否與該對象的相應字段匹配

  5. 完成后,檢查是否對稱、傳遞和一致

最后的警告:

  • 覆蓋 equals 時始終覆蓋 hashCode

  • 不要試圖太聰明

  • 不要在 equals 聲明中用其他類型替換 Object -> 不值得為了增加復雜性而獲得輕微的性能提升

來自 Effective Java 2nd Edition 的Hashcode直接引用

  1. 在名為 result 的 int 變量中存儲一些常量非零值,例如 17。

  2. 對于f對象中的每個重要字段(即 equals 方法考慮的每個字段),請執行以下操作:

    • 計算字段的 int 哈希碼 c:

    • 將步驟 2.a 中計算的哈希碼 c 合并到結果中,如下所示: result = 31 * result + c;

    1. 如果該字段是布爾值,則計算(f ? 1 : 0).

    2. 如果該字段是 byte, char, short, or int, compute (int) f.

    3. 如果該字段是 long, compute (int) (f ^ (f >>> 32)).

    4. 如果該字段是 float, compute Float.floatToIntBits(f).

    5. 如果字段是 a double, compute Double.doubleToLongBits(f),則對結果進行哈希處理long。

    6. 如果該字段是對象引用并且此類的 equals 方法通過遞歸調用比較該字段,則在該字段上equals遞歸調用hashCode。如果需要更復雜的比較,請為此字段計算“規范表示”并在規范表示上調用 hashCode。如果字段的值為nullreturn 0(或其他一些常數,但 0 是傳統的)。

    7. 如果該字段是一個數組,則將其視為每個元素都是一個單獨的字段。也就是說,通過遞歸應用這些規則來計算每個重要元素的哈希碼,并在步驟 2.b 中組合這些值。如果數組字段中的每個元素都很重要,則可以使用 1.5 版中添加的 Arrays.hashCode 方法之一。

  3. 返回結果。

  4. 當你寫完 hashCode 方法后,問問自己相等的實例是否有相等的哈希碼。編寫單元測試來驗證你的直覺!

所以遵循這些規則:

@Override

public boolean equals(Object obj) {


    if (this == obj) {

        return true;

    }


    if (!(obj instanceof Employee)) {

        return false;

    }

    Employee other = (Employee) obj;


    return super.equals(other) &&

           Double.compare(this.salary, other.salary) == 0 &&

           this.hireDay.equals(other.hireDay);


}

在您的情況下,雖然它似乎id應該已經唯一地標識任何人,所以您應該只使用它進行比較,而不是在任何子類中覆蓋它。


查看完整回答
反對 回復 2022-01-19
?
飲歌長嘯

TA貢獻1951條經驗 獲得超3個贊

如果你想實現 equals 和 hashcode 方法使用 eclipse 只需右鍵單擊文件轉到源并選擇 generate equals() & hashcode() 和你需要的字段,如下所示:

http://img1.sycdn.imooc.com//61e7d56f000125cc13640766.jpg

http://img1.sycdn.imooc.com//61e7d57700018bf013630770.jpg


查看完整回答
反對 回復 2022-01-19
?
陪伴而非守候

TA貢獻1757條經驗 獲得超8個贊

兩個人有沒有可能永遠一樣id?它不應該。所以邏輯延伸到Employee類,這意味著在類中實現equals和就足夠了。hashCodePerson

此時,由于您只處理一個int,您可以使用Integer.hashCode(id)forhashCode并僅比較 的值equals。


查看完整回答
反對 回復 2022-01-19
  • 3 回答
  • 0 關注
  • 169 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號