1. 程式人生 > 實用技巧 >Java學習路線:HashMap

Java學習路線:HashMap

在平常的開發當中,HashMap是我最常用的Map類(沒有之一),它支援null鍵和null值,是絕大部分利用鍵值對存取場景的首選。需要切記的一點是——HashMap不是執行緒安全的資料結構,所以不要在多執行緒場景中應用它。

通常情況下,我們使用Map的主要目的是用來放入(put)、訪問(get)或者刪除(remove),而對順序沒有特別的要求——HashMap在這種情況下就是最好的選擇。

01、Hash

對於HashMap來說,難理解的不在於Map,而在於Hash。

Hash,一般譯作“雜湊”,也有直接音譯為“雜湊”的,這玩意什麼意思呢?就是把任意長度的資料通過一種演算法對映到固定長度的域上(雜湊值)。

再直觀一點,就是對一串資料wang進行雜糅,輸出另外一段固定長度的資料er——作為資料wang的特徵。我們通常用一串指紋來對映某一個人,別小瞧手指頭那麼大點的指紋,在你所處的範圍內很難找出第二個和你相同的(人的雜湊演算法也好厲害,有沒有?)。

對於任意兩個不同的資料塊,其雜湊值相同的可能性極小,也就是說,對於一個給定的資料塊,找到和它雜湊值相同的資料塊極為困難。再者,對於一個數據塊,哪怕只改動它的一個位元位,其雜湊值的改動也會非常的大——這正是Hash存在的價值!

在Java中,String字串的雜湊值計算方法如下:

看得懂看不懂都沒關係,我們就當是一個“乘加迭代運算”的演算法。藉此機會,我們來看一下“沉”、“默”、“王”、“二”四個字串的雜湊值是多少。

輸出的結果如下(5位數字):

對於HashMap來說,Hash(key,鍵位)存在的目的是為了加速鍵值對的查詢(你想,如果電話薄不是按照人名的首字母排列的話,找一個人該多困難「我的微信好友有不少在暱稱前加了A,好狠」)。通常情況下,我們習慣使用String字串來作為Map的鍵,請看以下程式碼:

那HashMap會真的會將String字串作為實際的鍵嗎?我們來看HashMap的put方法原始碼:

雖然只有一個putVal()方法的呼叫,但是你應該已經發現,HashMap內部會把key進行一個hash運算,具體程式碼如下:

假如key是String字串的話,hash()會先獲取字串的hashCode(雜湊值),再對雜湊值進行位於運算,最終的值為HashMap實際的鍵(int值)。

既然HashMap在put的時候使用鍵的雜湊值作為實際的鍵,那麼在根據鍵獲取值的時候,自然也要先對get(key)方法的key進行hash運算,請看以下程式碼:

02、雜湊值衝突怎麼解決

儘管雜湊值很難重複,我們還是要明白,這種轉換是一種壓縮對映,也就是,雜湊值的空間通常遠小於輸入的空間,不同的輸入可能會雜湊成相同的輸出。

也就是說,key1 ≠ key2,但function(key1)有可能等於function(key2)——雜湊值衝突了。怎麼辦?

最容易想到的解決辦法就是:當關鍵字key2的雜湊值value與key1的雜湊值value出現衝突時,以value為基礎,產生另一個雜湊值value1,如果value1與value不再衝突,則將value1作為key2的雜湊值。

依照這個辦法,總會找到不衝突的那個。

03、初始容量和負載因子

HashMap的構造方法主要有三種:

其中initialCapacity為初始容量(預設為1 << 4 = 16),loadFactor為負載因子(預設為0.75)。初始容量是HashMap在建立時的容量(HashMap中桶的數量);負載因子是HashMap在其容量自動增加之前可以達到多滿的一種尺度。

當HashMap中的條目數超出了負載因子與當前容量的乘積時,則要對HashMap擴容,增加大約兩倍的桶數。

通常,預設的負載因子 (0.75) 是時間和空間成本上的一種折衷。負載因子過高雖然減少了空間開銷,但同時增加了查詢成本。如果負載因子過小,則初始容量要增大,否則會導致頻繁的擴容。

在設定初始容量時應該考慮到對映中所需的條目數及其載入因子,以便最大限度地減少擴容的操作次數。

如果能夠提前預知要存取的鍵值對數量的話,可以考慮設定合適的初始容量(大於“預估元素數量 / 負載因子”,並且是2的冪數)。

04、小結

在之前很長的一段時間內,我對HashMap的認知僅限於會用它的put(key, value)value = get(key)

但,當我強迫自己每週要輸出一篇Java方面的技術文章後,我對HashMap真的“深入淺出”了——雜湊值(雜湊值)、雜湊衝突(雜湊衝突)、初始容量和負載因子,竟然能站在我面前一直笑——而原先,我見到這些關鍵字就逃之夭夭了,我怕見到它們。

PS:如果大家在學習過程中遇到什麼問題,或者缺乏相關的學習資料,可檢視我的公告欄獲取,有問題隨問隨答,還有我這段時間整理的一些Java學習手冊,面試題,開發工具,PDF文件書籍教程,需要的話都可以免費分享給大家。