1. 程式人生 > >HashMap 的幾個要點

HashMap 的幾個要點

1、HashMap的資料結構是”連結串列雜湊”,具體如下:


2、兩個引數:initialCapacity 、loadFactor

其中initialCapacity 決定了上圖所示的table的被初始建立的長度,當然這還不是初始長度,初始長度是大於initialCapacity 的最小的2的n次方,(為什麼不能直接用initialCapacity作為初始長度呢?待會會分析到2的n次方的table長度的好處,一是可以優化取模的計算,如何優化待會分析。二是雜湊均勻,其實這就是取模的好處了)。 loadFactor*初始長度就是hashmap的擴容閾值,至於為什麼要擴容,那是因為要避免上圖的連結串列過長。
原始碼如下:
3、連結串列存的是什麼?
這裡有個問題,就是為什麼Entry為什麼不只存有key值就好,還要多存key的hash值呢? 先看一下hashmap的put方法的原始碼:
通過原始碼我們可以清晰看到HashMap儲存資料的過程為:首先判斷key是否為null,若為null,則直接呼叫putForNullKey方法。若不為空則先計算key的hash值,然後根據hash值搜尋在table陣列中的索引位置,如果table陣列在該位置處有元素,則通過比較是否存在相同的key,若存在則覆蓋原來key的value,否則將該元素儲存在鏈頭(最先儲存的元素放在鏈尾)。若table在該處沒有元素,則直接儲存。

其實put時,會呼叫key的兩個方法,一個是hashCode(),一個是equals(),兩個物件相等的條件是hashCode和equal相等,或者是hashcode()和key1==key2,其中hash()是將key轉化成一種新的表達,有key1!=key2 可以推出 hash(key1)!=hash(key2)。但是這對於數值型這個規律是滿足現實看法的。但是對於物件不一樣了,如我新建了兩個學生物件,存了相同的學生資訊,現實中這兩個物件是對應同一個學生的,所以這兩個物件應該是相等的,但是由於物件的地址空間不同,所以hashCode(key1)!=hashCode(key2),而且物件的key1.equal(key2)預設是key1==key2,所以程式判斷這兩個程式判斷這兩個物件是不相等的,這是有悖於實際的。
結論:hashcode()得到的一個數值,這是是物件的唯一的號,所以當hashcode相同的時,equals()得到的結果也應該相同,(因為hashcode相同說明兩個物件在現實生活中是等價的,所以它們比較的結果也應該是相同),所以我們對equals方法進行了重寫,建議一定要對hashCode方法重寫,以保證相同的物件返回相同的hash值,不同的物件返回不同的hash值。避免hashcode相同,而equals不同。 4、上圖的表長為什麼要是2的n次方? 為了避免key的hash值超過表的長度,所以必須對key的hash值做以下處理:hash(key)%length,其中length為表的長度,但是取模是很耗時的,所以能不能通過位的與操作來代替取模的操作呢?答案是:當length=2的n次時,hash(key)%length等價於 hash(key) &(length-1) 而取模的原始碼如下:

參考連結: http://mp.weixin.qq.com/s?__biz=MjM5MTM0NjQ2MQ==&mid=2650140213&idx=2&sn=3a921452cc4616caa12e70665c0f599d&chksm=beb7b44789c03d51f47624c493630059a4011a3f67aa9b6634decdcf5f403c565093187a067e&mpshare=1&scene=1&srcid=0225QS1R6PNzn7koY1cC6F0b#rd