1. 程式人生 > 其它 >hashcode與equals的關係,hashcode的作用

hashcode與equals的關係,hashcode的作用

一、hashcode與equals的關係

hashCode():將任意一個物件根據指定的演算法轉為32位int

equlas():比較兩個物件是否相等

equals相等的兩個物件,hashCode一定相等。hashCode相等的兩個物件,equals不一定相等。

  • 如果equals為true,hashcode一定相等;
  • 如果equals為false,hashcode不一定不相等;
  • 如果hashcode值相等,equals不一定相等;
  • 如果hashcode值不等,equals一定不等;

理解:

我們可以把hashCode()想象成一個函式f(x),equals就相當於是x軸座標,比如說我們學過的二次函式影象,當x軸相等的時候,f(x)一定相等。而當f(x)相等的時候,x座標卻不一定相等。

從另一個方面來理解,1%7 == 1,8%7 == 1,但是1和8是不相等的,這就是為什麼hashCode相等的兩個物件equals卻不一定相等,而equals相等,就相當於都是1%8==1,同樣都是1,hashCode當然相等。

程式設計者在設計一個類的時候為需要重寫equals方法,比如String類,但是千萬要注意,在重寫equals方法的同時,必須重寫hashCode方法

class Person2 {
    private Integer age;
    private String name;

    public Person2(Integer age, String name) {
        
this.age = age; this.name = name; } @Override public boolean equals(Object obj) { if (this == obj) return true; else if (!(obj instanceof Person2)) return false; //此時obj確實是Person的物件且與當前物件不是一個地址 Person2 per = (Person2) obj;
return this.name.equals(per.name) && this.age.equals(per.age); } } public class Test { public static void main(String[] args) { Person2 per1 = new Person2(20, "張三"); Person2 per2 = new Person2(20, "張三"); System.out.println(per1.equals(per2)); } }

二、hashcode的作用

hashCode方法的主要作用是為了配合基於雜湊的集合一起正常執行,這樣的雜湊集合包括HashSet、HashMap以及HashTable。

為什麼這麼說呢?考慮一種情況,當向集合中插入物件時,如何判別在集合中是否已經存在該物件了?(注意:集合中不允許重複的元素存在)

也許大多數人都會想到呼叫equals方法來逐個進行比較,這個方法確實可行。但是如果集合中已經存在一萬條資料或者更多的資料,如果採用equals方法去逐一比較,效率必然是一個問題。此時hashCode方法的作用就體現出來了,當集合要新增新的物件時,先呼叫這個物件的hashCode方法,得到對應的hashcode值,實際上在HashMap的具體實現中會用一個table儲存已經存進去的物件的hashcode值,如果table中沒有該hashcode值,它就可以直接存進去,不用再進行任何比較了;如果存在該hashcode值, 就呼叫它的equals方法與新元素進行比較,相同的話就不存了,不相同就雜湊其它的地址,所以這裡存在一個衝突解決的問題,這樣一來實際呼叫equals方法的次數就大大降低了,說通俗一點:Java中的hashCode方法就是根據一定的規則將與物件相關的資訊(比如物件的儲存地址,物件的欄位等)對映成一個數值,這個數值稱作為雜湊值。

下面這段程式碼是java.util.HashMap的中put方法的具體實現:

public V put(K key, V value) {
        if (key == null)
            return putForNullKey(value);
        int hash = hash(key.hashCode());
        int i = indexFor(hash, table.length);
        for (Entry<K,V> e = table[i]; e != null; e = e.next) {
            Object k;
            if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
                V oldValue = e.value;
                e.value = value;
                e.recordAccess(this);
                return oldValue;
            }
        }

        modCount++;
        addEntry(hash, key, value, i);
        return null;
    }

put方法是用來向HashMap中新增新的元素,從put方法的具體實現可知,會先呼叫hashCode方法得到該元素的hashCode值,然後檢視table中是否存在該hashCode值,如果存在則呼叫equals方法重新確定是否存在該元素,如果存在,則更新value值,否則將新的元素新增到HashMap中。從這裡可以看出,hashCode方法的存在是為了減少equals方法的呼叫次數,從而提高程式效率。

對於兩個物件,如果呼叫equals方法得到的結果為true,則兩個物件的hashcode值必定相等;如果equals方法得到的結果為false,則兩個物件的hashcode值不一定不同;如果兩個物件的hashcode值不等,則equals方法得到的結果必定為false;如果兩個物件的hashcode值相等,則equals方法得到的結果未知。