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方法得到的結果未知。