使用HashMap,如果key是自定義的類,就必須重寫hashcode()和equals()
hashcode()和equals()都繼承於object,在Object類中的定義為:
equals()方法在Object類中的定義:
return ( this == obj);
}
是一個本地方法,返回的對象的地址值。
1.hashcode()和equals()是在哪里被用到的?什么用的?HashMap是 基於散列函數, 以數組和鏈表的方式實現的。
而對於每一個對象,通過其hashCode()方法可為其生成一個整形值(散列碼),而默認自定義類Student 的hashcode是根據對象的引用算的,該整型值被處理后,將會作為數組下標,存放該對象所對應的Entry(存放該對象及其對應值)。
上邊由於兩個new Student(1,"aa")是不一樣的Student對象。而默認的Student類的hashcode是根據對象的引用算的。所以直接認為是兩個不一樣的對象,直接put進去了。所以需要重寫hashcode方法,如果hashcode不一樣則直接認為是不同對象
equals()方法則是在HashMap中插入值或查詢時會使用到。當HashMap中插入 值或查詢值對應的散列碼與數組中的散列碼相等時,則會通過equals方法比較key值是否相等,所以想以自建對象作為HashMap的key,必須重寫 該對象繼承object的equals方法。
2.本來不就有hashcode()和equals()了么?干嘛要重寫,直接用原來的不行么?
HashMap中,如果要比較key是否相等,要同時使用這兩個函數!因為自定義的類的hashcode()方法繼承於Object類,其hashcode碼為默認的內存地 址,這樣即便有相同含義的兩個對象,比較也是不相等的,例如,
Student st1 = new Student("wei","man");
Student st2 = new Student("wei","man");
正常理解這兩個對象再存入到hashMap中應該是相等的,但如果你不重寫 hashcode()方法的話,比較是其地址,不相等!
HashMap中的比較key是這樣的,先求出key的hashcode(),比較其值是否相等,若相等再比較equals(),若相等則認為他們是相等 的。若equals()不相等則認為他們不相等。如果只重寫hashcode()不重寫equals()方法,當比較equals()時只是看他們是否為 同一對象(即進行內存地址的比較),所以必定要兩個方法一起重寫。HashMap用來判斷key是否相等的方法,其實是調用了HashSet判斷加入元素 是否相等。這里由於兩個new Student(1,"aa")是不一樣的Student對象。而默認的Student類的hashcode是根據對象的引用算的。所以直接認為是兩個不一樣的對象,直接put進去了。所以需要重寫hashcode方法,如果hashcode不一樣則直接認為是不同對象,如下:
這里重寫的hashcode是一樣的,所以還是put進去了。所以還需要重新equals方法。其實是有這樣一個規定,如果hahscode一樣時,則還需要繼續調用equals方式看看對象是否相等。如下即可實現:
輸出:
可以看到如果hashcode不一樣就直接認為是不一樣的對象,不需要再去equal比較,更加節省時間。
如果new Student(1,"aa")、new Student(1,"bb")。通過code和name算出的hashcode就可以算是不一樣的對象,就不需要再去equals比較。
往往HashSet中存放的對象是否相等的邏輯都需要自己定義,而並不會直接用默認的引用來算,即一般都會重新hashcode和equals方法,而且同時需要重寫。以后要注意哦。
HashMap的 put和 get也類似。
HashMap是底層實現時數組加鏈表。
A.當put元素時:
1.首先根據put元素的key獲取hashcode,然后根據hashcode算出數組的下標位置,如果下標位置沒有元素,直接放入元素即可。
2.如果該下標位置有元素(即根據put元素的key算出的hashcode一樣即重復了),則需要已有元素和put元素的key對象比較equals方法,如果equals不一樣,則說明可以放入進map中。這里由於hashcode一樣,所以得出的數組下標位置相同。所以會在該數組位置創建一個鏈表,后put進入的元素到放鏈表頭,原來的元素向后移動。
B.當get元素時:
根據元素的key獲取hashcode,然后根據hashcode獲取數組下標位置,如果只有一個元素則直接取出。如果該位置一個鏈表,則需要調用equals方法遍 歷鏈表中的所有元素與當前的元素比較,得到真正想要的對象。
可以看出如果根據hashcdoe算出的數組位置盡量的均勻分布,則可以避免遍歷鏈表的情況,以提高性能。
所以要求重寫hashcode時,也要重寫equals方法。以保證他們是相同的比較邏輯