-
HashMap實際上是一個“鏈表散列”的數(shù)據(jù)結(jié)構(gòu),即數(shù)組和鏈表的結(jié)合體蹬挤。HashMap 底層就是一個數(shù)組結(jié)構(gòu)缚窿,數(shù)組中的每一項又是一個鏈表。當(dāng)新建一個 HashMap 的時候焰扳,就會初始化一個數(shù)組倦零。
hashCode常規(guī)協(xié)定:
- 在Java應(yīng)用程序執(zhí)行期間,在同一個對象上多次調(diào)用hashCode()方法時,必須一致的返回相同的整數(shù)吨悍,前提是對象上 equals 比較中所用的信息沒有被修改扫茅。從某一應(yīng)用程序的一次執(zhí)行到同一應(yīng)用程序的另一次執(zhí)行,該整數(shù)無需保持一致育瓜。
如果根據(jù) equals(Object) 方法葫隙,兩個對象是相等的,那么在兩個對象中的每個對象上調(diào)用 hashCode 方法都必須生成相同的整數(shù)結(jié)果躏仇。 - 以下情況不 是必需的:如果根據(jù) equals(java.lang.Object) 方法恋脚,兩個對象不相等,那么在兩個對象中的任一對象上調(diào)用 hashCode 方法必定會生成不同的整數(shù)結(jié)果焰手。但是糟描,程序員應(yīng)該知道,為不相等的對象生成不同整數(shù)結(jié)果可以提高哈希表的性能书妻。
- 當(dāng)equals方法被重寫時船响,通常有必要重寫 hashCode 方法,以維護(hù) hashCode 方法的常規(guī)協(xié)定,該協(xié)定聲明相等對象必須具有相等的哈希碼灿意。
- hashCode的存在主要是用于查找的快捷性,如Hashtable崇呵,HashMap等缤剧,hashCode是用來在散列存儲結(jié)構(gòu)中確定對象的存儲地址的;
- 如果兩個對象相同域慷,就是適用于equals(java.lang.Object) 方法荒辕,那么這兩個對象的hashCode一定要相同;
- 兩個對象的hashCode相同犹褒,并不一定表示兩個對象就相同抵窒,也就是不一定適用于equals(java.lang.Object) 方法,只能夠說明這兩個對象在散列存儲結(jié)構(gòu)中叠骑,如Hashtable李皇,他們“存放在同一個籃子里”。
對最后一條的說明:
hashCode是用來查找的:
比如內(nèi)存中有這樣的位置 :0 1 2 3 4 5 6 7
而我有個類宙枷,這個類有個字段叫ID,我要把這個類存放在以上8個位置之一掉房,如果不用hashcode而任意存放,那么當(dāng)查找時就需要到這八個位置里挨個去找慰丛,或者用二分法一類的算法卓囚。
而使用hashCode那就會使效率提高很多。我們這個類中有個字段叫ID,那么我們就定義我們的hashcode為ID%8诅病,然后把我們的類存放在取得得余數(shù)那個位置哪亿。比如我們的ID為9,9除8的余數(shù)為1贤笆,那么我們就把該類存在1這個位置蝇棉,如果ID是13,求得的余數(shù)是5苏潜,那么我們就把該類放在5這個位置银萍。這樣,以后在查找該類時就可以通過ID除 8求余數(shù)直接找到存放的位置了恤左。
但是如果兩個類有相同的hashcode怎么辦那(我們假設(shè)上面的類的ID不是唯一的)贴唇,例如9除以8和17除以8的余數(shù)都是1,那么這是不是合法的飞袋,回答是:可以這樣戳气。那么如何判斷呢?在這個時候就需要定義 equals了巧鸭。
也就是說瓶您,我們先通過 hashcode來判斷兩個類是否存放某個桶里,但這個桶里可能有很多類,那么我們就需要再通過 equals 來在這個桶里找到我們要的類呀袱。
那么贸毕。重寫了equals(),為什么還要重寫hashCode()呢夜赵?
想想明棍,你要在一個桶里找東西,你必須先要找到這個桶啊寇僧,你不通過重寫hashcode()來找到桶摊腋,光重寫equals()有什么用啊
總結(jié):
就像一開始那張圖片顯示的那樣,hashMap中的hashCode用來確認(rèn)要搜索的文件在數(shù)組中的位置嘁傀,但是由于可能存在兩個類可能存在同一個hashCode的情況兴蒸,就是說,一個數(shù)組的特定一個位置有可能存在多個數(shù)據(jù)细办,這在HasnMap中就表現(xiàn)為上圖中的那個鏈表橙凳,這個鏈表中存儲的對象擁有同樣的hashCode,所以查找的時候需要找到對象在數(shù)組中的位置,還需要和鏈表中的位置進(jìn)行對比笑撞。