阿了嗝歡的小白日記 HashMap(上)

2021-08-11 10:21:25 字數 2840 閱讀 7670

(說明:因為我最近用的是jdk1.7 截圖內容和大家實際接觸的略有不同。不過整體相差不遠,應該能看懂。)

所以,新部落格的第一篇文章就給了我個人認為最重要的集合之一——hashmap。

原始碼先不翻了,我對原始碼的剖析不夠細,論壇裡有太多大牛講解hashmap的原始碼的底層實現。

我就簡單的說一下自己的理解和總結。

從基礎說起:

hashmap是由鍵值對組成的雙列集合。

乙個key(鍵)對應乙個value(值)

key是唯一的。

1、那麼就來說一下key的唯一是如何實現的:

hashmap和list一樣,底層是靠陣列來實現的,不過要更高階一些。

hashmap由預設初始長度為16的節點陣列table構成(節點中儲存key,value和下乙個節點的引用),當我們呼叫put()方法想hashmap中存入資料時,方法內部會根據key值計算出乙個hash值,並通過hash值確定索要儲存的陣列索引(hash值的範圍一定在table.length-1範圍內)。 好吧還是簡單截兩張圖吧,不然光說很難理解。

首先是put()方法的:

hash()方法:

indexfor()方法:

在確定索引位置之後,會將儲存好key,value的節點物件存入對應的索引。(這句話需要注意一下,因為一會講到hashmap的資料結構雜湊表,會涉及到這裡)

但大家應該發現了,再新增節點到陣列中之前,有一段迴圈遍歷並做if判斷的操作,這段操作便是判斷存入的key是否已經才存在,如果存在,則用新value覆蓋之前的老value。如果不存在,則直接存入key,value鍵值對。

怎麼樣,乙個key值唯一的簡單解釋,涉及到了這麼多的知識點。不過看懂了之後,還是很過癮的。

2、剛剛說到節點中儲存的內容中提到了雜湊表,下面第二個點簡單說一下雜湊表的構成。

我們的都知道,hashmap的地城結構是雜湊表,那麼雜湊表又是什麼呢,雜湊表結構到底是如何實現的的?(這個問題在我剛接觸雜湊表也困擾了我很久,因為當時對節點和鍊錶等概念都非常模糊)

簡單的說,雜湊表就是剛剛說的節點陣列。

但陣列給人的感覺也是鏈狀的,「表」的實現還動用節點的結構。

剛剛說了節點中除了儲存key,value。還有下乙個節點的引用。

在解釋如何確保key唯一的原理時,是通過計算存入key的hash值來確定存入索引i的,但不同key也可能計算出相同的索引i。這時,會產生衝突(碰撞)。所以,我們要用鍊錶來解決。同索引下的節點物件通過next指向下乙個節點物件,從而形成鍊錶。新來的節點對映到衝突的索引位置時,只需要插入到對應的鍊錶即可

值得注意的是:hashmap中的鍊錶是單向鍊錶。並且新節點物件的插入採用的是「頭插法」。(簡單比喻一下就是說新來的節點物件會「擠掉」舊的節點物件,佔在陣列的索引位置,並在內部指向舊的節點物件)至於為什麼用「頭插法」我也不清楚,據說是因為hashmap的開發人員認為後插入的節點物件(也就是鍵值對)被查詢的可能性個更大(至於為什麼被查詢的可能性大就放在用「頭插法」接下來馬上說明)。阿歡自我理解:其實從key唯一角度來考慮,這樣的解釋也不無道理。改變key,value鍵值對中的value時,用的也是put()方法,也就是變相的儲存。修改次數越多,被放在索引位置的機率越大,也越說明該鍵值對被重視的程度越大,也就是被查詢利用的機率越大。哈哈哈,以上純屬來自乙個雙魚座的個人想象和理解。看得懂的話可以互相分享一下想法。(這說說到的查詢,也需大家注意一下,因為接下來我們就來介紹一下查詢get()方法)

3、說完儲存,自然要說一下查取

剛剛我們已經知道,雜湊表由陣列和鍊錶構成。也就是說雜湊表兼備陣列的查詢快和鍊錶的增刪快特點。(對應arraylist和linkedlist)

直接上馬!駕!

第一張是get()方法的原始碼,很好理解。重點是getentry()這個方法。

接下來看一下getentry() :(在這裡我有乙個疑問,在get方法中已經對key判過一次空了,為什麼到getentry中還要再判斷一次呢?我個人的猜想是防止併發訪問時,在get判斷不為空後,在直接行getentry判空之前,有其他執行緒對當前的key進行了刪除操作或者對map進行了clean操作二導致報錯。請大牛解答一下是否正確或者還有其他原因)

這個方法也很簡單,先確定索要查詢的table陣列索引,然後從頭結點開始遍歷查詢對應的key值並獲取對應的value。(這裡涉及到時間複雜度的問題,對於時間複雜度我也是有淺顯的認識,大家可以查一下大牛們的資料。以後如果我對此有更深的認識也會寫相應日記)

簡單來說,因為查詢是從頭結點開始的,所以要查詢的目標節點距離頭結點越近,那麼查到的速度就越快。現在回想一下剛剛為什麼put()方法要用「頭插法」來進行是不是也能理解了。

好了 就先簡單說下儲存和查取。

因為是想寫就寫了,也沒什麼準備。看來再寫文章還是先打乙個簡單的草稿,準備好畫圖工具比較好。

我也是小白乙個(技術和文筆都是)。希望看客老爺們多多見諒,希望大家共同進步!

下篇文章繼續介紹hashmap,重點說一下在自己使用和面試中常見的問題和原理。

————急需進步的阿歡

小白日記 網路層的路由概述

路由演算法實際上就是圖論的演算法。但是路由演算法不單單是圖論演算法,因為網路環境很複雜。對演算法的要求 演算法是正確 完整的。演算法在計算上應該盡可能的簡單。演算法可以適應網路中的變化 演算法是穩定的和公平的 即使這個裝置發生故障,也不會影響其他裝置,公平就是什麼裝置都一樣,不會因為裝置不一樣就區別...

小白日記 Java中多型的理解隨記

題外話 當初硬頭皮承接專案之時,就已經做好了邊學習邊做專案的打算。這樣以來可以極大的縮短學習時間。先試著做,哪不會了再學習 好處是可以在實踐當中積累豐富的經驗,但缺點是這樣的方式對知識的掌握紮實程度遠遠不如一步乙個腳印的學過來 待後期有充足時間之後再整體性的對知識進行乙個補足。btw,簡單說一下現在...

SLAM小白日記 Eigen庫的轉化使用

題目 已知旋轉矩陣定義是沿著z軸旋轉45 按照該定義初始化旋轉向量 旋轉矩陣 四元數 尤拉角。請程式設計實現 1 以上四種表達方式的相互轉換關係並輸出,看看是否正確 2 假設平移向量為 1,2,3 請輸出旋轉矩陣和該平移矩陣構成的歐式變換矩陣,並根據歐式變換矩陣提取旋轉向量及平移向量 本程式學習目標...