重寫equals()方法的注意事項及其原因,爲什麼重寫equals()時需要hashCode()方法?

爲什麼要重寫equals()方法?

因爲默認equals在比較兩個對象時,是看他們是否指向同一個地址的。但有時,我們需要兩個不同對象只要是某些屬性相同就認爲它們equals()的結果爲true。比如:

person p1 = new person(1,"name");
person p2 = new person(1,"name");
如果不重寫equals的話,他們是不相同的,所以我們要重些equals,判斷只要他們的id和名字相同equals就爲true,在一些集合裏有時也這樣用,集合裏的contain也是用equals來比較

 

Object關於equals()的源碼:

    public boolean equals(Object obj) {
        return (this == obj);
    }

重寫需要注意的屬性:

equals方法實現了一個等價關係(equivalence relation)。它有以下這些屬性:
• 自反性:對於任何非空引用x,x.equals(x)必須返回true。
• 對稱性:對於任何非空引用x和y,如果且僅當y.equals(x)返回true時x.equals(y)必須返回true。
• 傳遞性:對於任何非空引用x、y、z,如果x.equals(y)返回true,y.equals(z)返回true,則x.equals(z)必須返回true。
• 一致性:對於任何非空引用x和y,如果在equals比較中使用的信息沒有修改,則x.equals(y)的多次調用必須始終返回true或始終返回false。
• 非空性: 對於任何非空引用x,x.equals(null)必須返回false。
當重寫equals方法時,同時也要重寫hashCode方法。

重寫equals()的例子:

public final class Person {

    private final short height, weight;

    public PhoneNumber(short heightnum, short weightnum) {
        this.heightnum= height;
        this.weightnum= weight;
       
    }


    @Override
    public boolean equals(Object o) {
        if (o == this)
            return true;
        if (!(o instanceof Person))
            return false;
        if (o == null)
            return false;

        Person p = (Person) o;

        return p.height == this.height && p.weight == this.weight;
    }

}

注:重寫equals()很多時候需要重寫hashCode()!

 

首先先弄清楚hashCode()是用來幹嘛的?

一提到hashcode,很自然就想到哈希表。將某一key值映射到表中的一個位置,從而達到以O(1)的時間複雜度來查詢該key值。Object類源碼(如下所示)中,hashCode()是一個native方法,哈希值的計算利用的是內存地址。

 

Object中hashcode()的源碼:

public native int hashCode();

上面使用了native關鍵字,說明這是一個本地方法。使用了native關鍵字的方法就說明這個方法是一個調用Java本地接口(Java Native Interface,即JNI)實現的方法。

 

什麼是JNI(Java本地接口)?

簡單點說,就是用其他編程語言,主要是C或C++或彙編語言實現的接口。

通過JNI,Java可以調用一些由其他語言開發的功能,或者可以被其他的語言所調用,從而實現了Java和其他語言的雙向連接。

 

什麼時候需要重寫hashCode()方法?

在每個類中,在重寫 equals 方法的時侯,一定要重寫 hashcode 方法。如果不這樣做,你的類違反了hashCode的通用約定,這會阻止它在HashMap和HashSet這樣的集合中正常工作。

 

hashCode()方法和equals()方法的關係

1. 如果兩個對象相同(即用equals比較返回true),那麼它們的hashCode值一定要相同!!!!; 
2. 如果兩個對象不同(即用equals比較返回false),那麼它們的hashCode值可能相同也可能不同; 
3. 如果兩個對象的hashCode相同(存在哈希衝突),那麼它們可能相同也可能不同(即equals比較可能是false也可能是true) 
4. 如果兩個對象的hashCode不同,那麼他們肯定不同(即用equals比較返回false)
 

爲什麼重寫equals()就要重寫hashCode()方法?

對於對象集合的判重,如果一個集合含有10000個對象實例,僅僅使用equals()方法的話,那麼對於一個對象判重就需要比較10000次,隨着集合規模的增大,時間開銷是很大的。但是同時使用哈希表的話,就能快速定位到對象的大概存儲位置,並且在定位到大概存儲位置後,後續比較過程中,如果兩個對象的hashCode不相同,也不再需要調用equals()方法,從而大大減少了equals()比較次數。 
所以從程序實現原理上來講的話,既需要equals()方法,也需要hashCode()方法。那麼既然重寫了equals(),那麼也要重寫hashCode()方法,以保證兩者之間的配合關係。
 

僅僅重寫了equals(),而沒有重寫hashCode()方法,會出現什麼情況? 

字段屬性值完全相同的兩個對象因爲hashCode不同,所以在hashmap中的table數組的下標不同,從而這兩個對象就會同時存在於集合中,所以重寫equals()就一定要重寫hashCode()方法。

但是應該是有個前提,就是你需要用到HashMap,HashSet等Java集合。用不到哈希表的話,其實僅僅重寫equals()方法也可以吧。而工作中的場景是常常用到Java集合,所以Java官方建議 重寫equals()就一定要重寫hashCode()方法。 
 

 

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