今天就跟大家聊聊有關HashMap的作用是什么,可能很多人都不太了解,為了讓大家更加了解,小編給大家總結了以下內容,希望大家根據這篇文章可以有所收獲。
創新互聯成立與2013年,我們提供高端網站建設、微信平臺小程序開發、電商視覺設計、APP應用開發及網絡營銷搜索優化服務,在傳統互聯網與移動互聯網發展的背景下,我們堅守著用標準的設計方案與技術開發實力作基礎,以企業及品牌的互聯網商業目標為核心,為客戶打造具商業價值與用戶體驗的互聯網+產品。
工作原理
首先是或者對插入對象的key的hash指進行擾動得到新的hash值,簡單來講是為了更好的散列
根據hash值找到需要插入值的下標,然后對鏈表進行相應的操作,在末尾插入,hash沖突,轉化成紅黑樹
如果有需要,則進行擴容
獲取值的時候就比較簡單了,直接根據key的hash找到桶的下標,再遍歷鏈表找到值就好了。
注意:key對象本身有個hash值,但是put和get的時候是經過了hash算法進行了擾動生成了新的hash值,但是對象本身的hash值不變。
肯定是挑重點的說先,其它的有了基礎后可以自行去源碼中查找學習,這樣更有成就感。
通過一開始也知道,HashMap
是由數組加鏈表組成的,其實本質就是多個下面Node<K,V>
組成的數組 。
<img src="/upload/otherpic50/node-hashmap.png" alt="node-hashmap" />
其實好像也沒啥好講的,知道有這么一個類,類里面有那些成員變量就好了。
可能有小伙伴會發現了,怎么沒有capcity
容量這個成員變量呀。需要注意的是jdk1.8之后,桶數組的初始化不是在構造函數內完成的,而是在第一次put的時候完成的,所以不設capcity
這個變量完全沒問題。
構造函數大體來說有兩種,一種是給成員變量賦值,一種是復制一個新的map
上面有兩個函數tableSizeFor()
和putMapEntries()
有興趣的小伙伴可以去看下源碼,實現比較簡單,這里就不再贅述。
讓我們來看下put的源碼
public V put(K key, V value) { return putVal(hash(key), key, value, false, true); }
首先運行的是一個hash()
的函數
static final int hash(Object key) {//hash算法 int h; return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16); }
首先int h = key.hashCode()
h是一個4字節32位的數,接著是異或上h >>> 16
最后得到了新的hash值。
h是個32位的數,那么它右移16位后,高位(前16位)位0,而x ^ 0 = x。所以整個上面一句話的作用就是保留高位,低位和高位異或,這樣子能達到的目標就是擾亂了低位,且低位具有高位的一部分屬性。
接下來的重點就到了putVal()
,需要分位第一次put和其它put來講。
第一次put時候的putVal()
final V putVal(int hash, K key, V value, boolean onlyIfAbsent, boolean evict) { Node<K,V>[] tab; Node<K,V> p; int n, i; if ((tab = table) == null || (n = tab.length) == 0) n = (tab = resize()).length; //..... }
當第一次put的時候,table肯定是為空的,也就是if ((tab = table) == null || (n = tab.length) == 0)
判斷返回為true,走到resize()
流程。
來看看第一次put的時候resize是怎么運作的
通過源碼可以看到真正的table數組是在第一次put中的putVal()
中的resize()
時才初始化。
看源碼,首先會有一個根據hash計算該key應該放在哪個桶下面,n是桶數組的長度,永遠是2的冪。反映在二進制就是只有某一位是1,其它全是0。這樣的情況下,n - 1就是尾部全是1,其它全是0。(n - 1) & hash就是保留hash值中數組長度低位的數,高位的數置0。
假設n = 16,那么n - 1 = 15 = 00001111,這樣與上hash相當于只保留了hash的后4位。
可以發現上述源碼中在最后還有一個resize()
,可見resize()
除了初始化的時候有用,更多時候是用在擴容這方面。
上面源碼注釋中也有寫到是當k-v個數 > 擴容閾值 = table數組容量 * 負載因子(默認是0.75)
的時候開始擴容,table數組變成原來的2倍,舊k-v重新散列在新數組中。
我把后面的拆開來說,因為其一是因為其巧妙,其二是因為太長了看著疲憊
可以提前說下,jdk的思想是把鏈表拆分成兩部分進行散列。想拆成2部分必須用hash經過某種運算得到兩種結果,計算機里面自然就想到了0,1。一個數和另一個數得到0和1,所以可以想到&運算,且其中一個數只有1位是1,其它都是0。
所以算法就是那hash(注意,是擾動前的hash)& newCap
這樣得到的結果就只有0和1了。
相比之前的插入和擴容函數,get()
相對來說就簡單了
public V get(Object key) { Node<K,V> e; return (e = getNode(hash(key), key)) == null ? null : e.value; }
可以看到最終是到了getNode()
函數
看完上述內容,你們對HashMap的作用是什么有進一步的了解嗎?如果還想了解更多知識或者相關內容,請關注創新互聯行業資訊頻道,感謝大家的支持。
標題名稱:HashMap的作用是什么
網站網址:http://m.newbst.com/article46/gdcieg.html
成都網站建設公司_創新互聯,為您提供定制開發、網站設計、網站導航、網站設計公司、面包屑導航、企業建站
聲明:本網站發布的內容(圖片、視頻和文字)以用戶投稿、用戶轉載內容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網站立場,如需處理請聯系客服。電話:028-86922220;郵箱:631063699@qq.com。內容未經允許不得轉載,或轉載時需注明來源: 創新互聯