JDK是如何判斷兩個物件是否相同的?判斷的流程是什麼?

AlanKeene發表於2019-02-23

JDK 是如何判斷兩個物件是否相同的呢?判斷的流程是什麼?

參考解答: JDK 會先判斷兩個物件的hashCode是否相同,如果hashCode不同,則說明肯定是兩個不同的物件了;如果hashCode相同再通過equals()方法進行進一步比較,如果equals方法返回true,則說明兩個物件是相同的,如果equals方法返回false說明兩個物件不同。

如何驗證

怎麼來驗證這個問題呢?我們知道HashSet是不允許儲存相同的鍵值的。所以我們可以用HashSet儲存兩個相同的鍵值來模擬,看JDK是如何做判斷和識別的,從而驗證我們的猜想。

// 先自定義一個類並複寫 hashCode 和 equals 方法

public class CustomClass {

    @Override
    public int hashCode() {
        System.out.println("判斷 hashCode");
        return 1; // 返回1,說明所有新建的物件的雜湊值都為1,也就是相同
    }

    @Override
    public boolean equals(Object o) {
        System.out.println("判斷 equals");
        return true; // 返回true
    }
}
複製程式碼

接下來我們用HashSet來儲存兩個自定義的CustomClass的物件,程式碼如下:

public class HashSetTest {
    public static void main(String[] args) {
      
        HashSet<CustomClass> hs = new HashSet<>();
        CustomClass cs1 = new CustomClass();
        CustomClass cs2 = new CustomClass();
        hs.add(cs1);
        hs.add(cs2);
        System.out.println("----hs新增完畢");
        System.out.println("hs:"+hs); // 列印一下hashSet集合看裡面存放了什麼

    }
}
複製程式碼

列印結果如下:

判斷 hashCode 
判斷 hashCode
判斷 equals
----hs新增完畢
判斷 hashCode // 此處的判斷是列印輸出語句執行時呼叫的,與分析本問題無關
hs:[com.alankeene.javalib.collections.CustomClass@1]
複製程式碼

結果分析: 執行 hs.add(cs1) 語句的時候,JDK 會先判斷 cs1 所指向物件的hashCode,因為是第一次往HashSet集合裡面存放元素,該元素 hashCode 在集合中肯定是還沒存在的,這是個新的元素,所以直接存放進集合中,不用呼叫 cs1 所指向物件的 equals 方法。 當執行 hs.add(cs2) 語句時,這是第二次往集合裡存放元素,有新的元素 cs2 要新增進來,那先要呼叫 cs2 所指向物件的 hashCode 方法看看它的雜湊值是不是與集合中已有元素的雜湊值重複了,發現重複了,雜湊值都是1,那有可能是同一個物件,那就要呼叫 cs2 所指向物件的 equals 方法做進一步判斷,發現 equals 方法返回 true,則判斷為是重複的元素,就不往集合裡新增了。

所以最終列印 HashSet 集合的時候可以看到,集合中只存放了一個元素。

注:所以平時我們在自定義一個類時,要謹慎把 equals 方法的返回值靜態的設定為 true,因為一旦產生雜湊衝突,JDK 就會認為相同雜湊值的物件就是同一個物件了。

我們再反證一下,把 equals 方法改為返回 false,模擬兩個hashCode相同,但是是兩個不同的物件的情景。

public class CustomClass {

    @Override
    public int hashCode() {
        System.out.println("判斷 hashCode");
        return 1; // 返回1,說明所有新建的物件的雜湊值都為1,也就是相同
    }

    @Override
    public boolean equals(Object o) {
        System.out.println("判斷 equals");
        return false; // 返回false
    }
}
複製程式碼

列印結果會如下:

判斷 hashCode 
判斷 hashCode
判斷 equals
----hs新增完畢
判斷 hashCode // 此處的判斷是列印輸出語句執行時呼叫的,與分析本問題無關
判斷 hashCode // 此處的判斷是列印輸出語句執行時呼叫的,與分析本問題無關
hs:[com.alankeene.javalib.collections.CustomClass@1, com.alankeene.javalib.collections.CustomClass@1]
複製程式碼

會發現,HashSet集合中存放了兩個元素了,說明雖然 cs1 和 cs2 的雜湊值相同,但是 JDK 判斷為不同的元素並存入集合中了。

由此,驗證了我們的猜想。JDK 是先判斷 hashCode,如果 hashCode 相同再通過 equals 去判斷兩個物件是否相同的。

相關文章