在java集合中,HashMap是用來存放一組鍵值對的數,也就是key-value形式的資料,而在jdk1.6和jdk1.8的實作有所不同。
JDK1.6的源碼實作:
首先來看一下HashMap的類的定義:

HashMap繼承了AbstractHashMap,實作了Map,Cloneable和Serializable接口,Map定義了一些公共的接口,而AbstractHashMap也實作了Map接口,并提供了一些預設的實作,如size方法和isEmpty方法等
在HashMap中,定義了幾個常量:
初始容量,如果在建立HashMap的時候沒有指定容量,就使用初始容量
最大容量,HashMap中存儲元素的數組的最大的容量,為2的30次方
預設的加載因子,在擴容的時候使用
最重要的一個常量,用來存放我們添加的元素,
門檻值,用來判斷HashMap是否需要擴容,如果添加的元素超過該值,則需要擴容, 該值等于 capacity * loadFactor,比如 預設的初始容量為16, 預設的加載因子為0.75,則門檻值就等于16*0.75=12,在table數組中,如果數組的元素個數超過12,則table數組就需要進行擴容。
HashMap提供了三個構造方法,我們可以指定初始容量和加載因子來構造HashMap
也可以隻指定初始容量來構造HashMap
也可以都不指定,這時,初始容量和加載因子都是用的預設的值,一般情況下也不會去指定初始容量和加載因子。
如果采用不帶參數的構造方法,可以看到存放元素的初始數組的大小為16,門檻值為12。
相當于 Entry[] table = new Entry[16],在HashMap内部使用 Entry數組來存放元素的。
可以看到Entry表示的是一個單向連結清單的結構,next就是指向下一個節點;也就是說在HashMap内部,使用數組+連結清單的形式來存放元素,數組的每一項就是一個連結清單。HashMap的結構圖大緻如下所示:
接下來看一下對HashMap的常用操作:
1. put(key, value)操作,向HashMap中添加元素
1)添加的時候,首先要計算key的hash值,找到對應數組的下标
2)找到該下标對應的數組位置的連結清單,周遊連結清單,把值添加到該連結清單上
addEntry()方法如下:
用圖來說明:
1. 初始化一個空的HashMap,此時還沒有元素,結構如下:
假設要添加一對資料:key="zs", value="zhangsan"
首先對 key進行hash,比如 hash之後的值為5,之後在用hash和table.length來求數組的索引,
比如索引 i = 4,此時,這對元素就應該在 table[i] 即 table[4] 的位置處,取得該處的Entry連結清單,此時,連結清單為空,建立一個Entry節點,加入到該空連結清單中:
此時,在添加一對元素:key="ls", value="lisi",假如計算的索引 i 恰好等于4,此時,取得 table[4] 處的連結清單 Entry<K, V> = table[4], 用key = "ls"在這個連結清單上進行周遊,看看是否該key已存在:
此時,key="ls"并不存在,又會建立一個Entry節點,加入到該清單中:
如果此時,又添加 key="zs", value="zhangsan222",根據key計算到的索引為4,取出 table[4]處的連結清單,周遊連結清單,然後檢查對應的key是否存在,檢查到key已經存在了,是以會把新的值替換舊的值即可,不用建立新的節點。
2.get(key)操作
1)根據key計算hash值,根據hash值和數組長度計算數組的下标索引
2)取得該下标對應的連結清單,周遊連結清單,找到key對應的value
3.remove()操作,
1)根據key計算hash值,根據hash值和數組長度計算數組的下标索引
2)取得該下标對應的連結清單,周遊連結清單,删除key對應的Entry節點
removeEntryForKey()方法如下:
假設現在HashMap中元素的分布如下:
要删除 key="ls"的元素,假如計算的索引 i=4,要去周遊 table[4]處的連結清單,删除對應的節點,key="ls"為連結清單的第一個節點:
以上就是jdk1.6中HashMap的實作,是基于數組+連結清單的形式來存放資料的。
JDK1.8的源碼實作:
在JDK1.8中,HashMap的實作比1.6的實作要複雜得多,1.8中引入了紅黑樹的資料結構;
除了上面列出來的常量外,新增加了幾個常量:
表示的是,如果數組中連結清單的元素大于該值,則需要把該連結清單轉化為紅黑樹,
如果連結清單中的元素個數小于該值,則把紅黑樹轉換為連結清單
在JDK1.6中,使用一個Entry數組來存放元素,而在JDK1.8中,使用的Node數組和TreeNode來存放元素,
Node:其實,Node和Entry沒有什麼差別,
TreeNode:表示的是一個紅黑樹結構