關於equals()和hashcode()的一些約定


本文章主要討論和回答一下幾個問題:

  • equals()的四大特性

  • equals()和hashcode()之間的關系,為什么我們經常說這兩個方法要么都重寫,要么都不重寫?

  • HashMap、HashSet等容器為什么要求一定要重寫equals()以及hashcode()

equals()

equals和hashcode方法我們都很了解,是Object類中的定義的方法,這意味着所有的類都隱式實現了這兩個方法。

Object類中的equals方法的默認實現是比較對象標識(根據對象頭信息),但是這個對我們沒有任何意義。因此一般情況下我們要重寫equals方法

equals方法一般有以下四個約定:

  • 自反:對象必須等於自身

  • 對稱:x.equals(y) 必須返回與 y.equals(x) 相同的結果

  • 傳遞性:如果 x.equals(y) 和 y.equals(z) 那么 x.equals(z)

  • 一致:僅當包含在 equals() 中的屬性發生更改時,equals() 的值才應更改

使用IDEA智能重寫equals方法如下,比較兩個對象相關屬性的值是否全部一致。:

public class Student {
    private String name;
    private int age;
}
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Student student = (Student) o;
        return age == student.age && Objects.equals(name, student.name);
    }

hashcode()

hashcode方法也同樣定義在Object類中,返回一個整數,表示該類的實例狀態,要根據類的相等性定義來計算這個值,也就是說hashcode方法調用了equals方法,因此重寫hashcode必須先重寫equals,這樣類的hashcode值才有意義。

hashcode同樣有取得共識的約定:

  • 內部一致性:只有當 equals() 中的屬性發生變化時,hashCode() 的值才會發生變化
  • 相等一致性:彼此相等的對象必須返回相同的 hashCode
  • hash碰撞:不相等的對象可能具有相同的哈希碼

從第二個約定我們可以推出,重寫equals方法也必須同時重寫hashcode方法,不然就違反了第二個規定

看到這里,我想我們已經解決了前面提出的第二個問題,equals和hashcode必須都被重寫或者都不重寫

但是,這只是一個約定,並非強制要求,如果不遵循這個約定會有什么問題呢?我們通過hashmap來舉例

hashmap的key如何實現唯一性

我們知道map為了保證map的key是唯一的,我們需要重寫key類的hashcode方法和equals方法。為什么呢?因為key的添加過程是這樣的:

  • 先查看key的hashcode是否已經存在

    • 如果不存在,說明當前容器沒有此key,直接添加

    • 如果存在,有可能是相同的key,也有可能是產生了hash碰撞。使用equals進行進一步比較

因此使用hashmap必須重寫這兩個方法

如果不重寫的話,可能會有重復的key被放入map中。舉個例子:

        HashMap<Student, Integer> studentIntegerHashMap = new HashMap<Student, Integer>();
        Student tom1 = new Student("tom", 11);
        Student tom2 = new Student("tom", 11);
        studentIntegerHashMap.put(tom1,1);
        studentIntegerHashMap.put(tom2,1);

正常情況下tom2是不會被添加到map集合中的,但是如果你不重寫hashcode方法,使用的就是本地的hashcode方法,這兩個對象的hashcode一定不同,因此都能被添加進集合中,這顯然是我們不想看到的。

至於HashSet,有的朋友應該知道,HashSet的底層是通過HashMap實現的,因此也同樣要實現這兩個方法才能“去重”

總結

在本篇文章中,我們討論了 equals() 和 hashCode() 的約定和使用。我們應該記住以下幾點:

  • 如果我們覆蓋 equals(),則始終覆蓋 hashCode(),反過來也一樣

  • 考慮使用 IDE 或第三方庫來生成 equals() 和 hashCode() 方法

參考


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM