HashMap的底层原理
一:HashMap的節(jié)點:HashMap是一個集合,鍵值對的集合,源碼中每個節(jié)點用Node<K,V>表示
static class Node<K,V> implements Map.Entry<K,V> {final int hash;final K key;V value;Node<K,V> next;Node是一個內(nèi)部類,這里的key為鍵,value為值,next指向下一個元素,可以看出HashMap中的元素不是一個單純的鍵值對,還包含下一個元素的引用。
二:HashMap的數(shù)據(jù)結(jié)構(gòu):HashMap的數(shù)據(jù)結(jié)構(gòu)為 數(shù)組+(鏈表或紅黑樹),上圖:
為什么采用這種結(jié)構(gòu)來存儲元素呢?
數(shù)組的特點:查詢效率高,插入,刪除效率低。
鏈表的特點:查詢效率低,插入刪除效率高。
在HashMap底層使用數(shù)組加(鏈表或紅黑樹)的結(jié)構(gòu)完美的解決了數(shù)組和鏈表的問題,使得查詢和插入,刪除的效率都很高。
三:HashMap存儲元素的過程:
有這樣一段代碼:
HashMap<String,String> map = new HashMap<String,String>(); map.put("劉德華","張惠妹"); map.put("張學(xué)友","大S");現(xiàn)在我要把鍵值對 “劉德華”,”張惠妹”存入map:
第一步:計算出鍵“劉德華”的hashcode,該值用來定位要將這個元素存放到數(shù)組中的什么位置.
什么是hashcode?
在Object類中有一個方法:
public native int hashCode();該方法用native修飾,所以是一個本地方法,所謂本地方法就是非java代碼,這個代碼通常用c或c++寫成,在java中可以去調(diào)用它。
調(diào)用這個方法會生成一個int型的整數(shù),我們叫它哈希碼,哈希碼和調(diào)用它的對象地址和內(nèi)容有關(guān).
哈希碼的特點是:
對于同一個對象如果沒有被修改(使用equals比較返回true)那么無論何時它的hashcode值都是相同的
對于兩個對象如果他們的equals返回false,那么他們的hashcode值也有可能相等
明白了hashcode我們再來看元素如何通過hashcode定位到要存儲在數(shù)組的哪里,通過hashcode值和數(shù)組長度取模我們可以得到元素存儲的下標(biāo)。
劉德華的hashcode為20977295 數(shù)組長度為 16則要存儲在數(shù)組索引為 20977295%16=1的地方
可以分兩種情況:
數(shù)組索引為1的地方是空的,這種情況很簡單,直接將元素放進去就好了。
已經(jīng)有元素占據(jù)了索引為1的位置,這種情況下我們需要判斷一下該位置的元素和當(dāng)前元素是否相等,使用equals來比較。
如果使用默認的規(guī)則是比較兩個對象的地址。也就是兩者需要是同一個對象才相等,當(dāng)然我們也可以重寫equals方法來實現(xiàn)我們自己的比較規(guī)則最常見的是通過比較屬性值來判斷是否相等。
如果兩者相等則直接覆蓋,如果不等則在原元素下面使用鏈表的結(jié)構(gòu)存儲該元素
每個元素節(jié)點都有一個next屬性指向下一個節(jié)點,這里由數(shù)組結(jié)構(gòu)變成了數(shù)組+鏈表結(jié)構(gòu),紅黑樹又是怎么回事呢?
因為鏈表中元素太多的時候會影響查找效率,所以當(dāng)鏈表的元素個數(shù)達到8的時候使用鏈表存儲就轉(zhuǎn)變成了使用紅黑樹存儲,原因就是紅黑樹是平衡二叉樹,在查找性能方面比鏈表要高.
**四:HashMap中的兩個重要的參數(shù):**HashMap中有兩個重要的參數(shù):初始容量大小和加載因子,初始容量大小是創(chuàng)建時給數(shù)組分配的容量大小,默認值為16,用數(shù)組容量大小乘以加載因子得到一個值,一旦數(shù)組中存儲的元素個數(shù)超過該值就會調(diào)用rehash方法將數(shù)組容量增加到原來的兩倍,專業(yè)術(shù)語叫做擴容.
在做擴容的時候會生成一個新的數(shù)組,原來的所有數(shù)據(jù)需要重新計算哈希碼值重新分配到新的數(shù)組,所以擴容的操作非常消耗性能.
創(chuàng)建HashMap時我們可以通過合理的設(shè)置初始容量大小來達到盡量少的擴容的目的。加載因子也可以設(shè)置,但是除非特殊情況不建議設(shè)置.
總結(jié)
以上是生活随笔為你收集整理的HashMap的底层原理的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 程序员你真的理解final关键字吗?
- 下一篇: linux内核杂记(9)-进程调度(4)