一.那么關(guān)于遇到hash沖突時候這個數(shù)據(jù)是頭插呢?還是尾插呢?
關(guān)于HashMap鏈表插入問題,java8之前之前是頭插法
頭插法:就是說新來的值會取代原有的值绎谦,原有的值就順推到鏈表中去福澡,就像上面的例子一樣,因為寫這個代碼的作者認(rèn)為后來的值被查找的可能性更大一點胧华,提升查找的效率。
在java8之后彻秆,都是所用尾部插入了柬泽。
效
解決上面的問題需要一些預(yù)備知識
hashmap的擴容原理
hashmap擴容分為兩步
- 擴容:創(chuàng)建一個新的Entry空數(shù)組框喳,長度是原數(shù)組的2倍课幕。
- ReHash:遍歷原Entry數(shù)組,把所有的Entry重新Hash到新數(shù)組五垮。
為什么要重新Hash呢乍惊,不直接復(fù)制過去呢?
因為長度擴大以后放仗,Hash的規(guī)則也隨之改變润绎。
Hash的公式---> index = HashCode(Key) & (Length - 1)
原來長度(Length)是8你位運算出來的值是2 ,新的長度是16你位運算出來的值明顯不一樣了,之前的所有數(shù)據(jù)的hash值得到的位置都需要變化诞挨。
如下圖:
擴容前:
擴容后:
主要是為了安全,防止環(huán)化
因為resize的賦值方式,也就是使用了單鏈表的頭插入方式惶傻,同一位置上新元素總會被放在鏈表的頭部位置棍郎,在舊數(shù)組中同一條Entry鏈上的元素,通過重新計算索引位置后达罗,有可能被放到了新數(shù)組的不同位置上坝撑。
就可能出現(xiàn)下面的情況,大家發(fā)現(xiàn)問題沒有粮揉?
B的下一個指針指向了A如果這個時候去取值,就出現(xiàn)了無限循環(huán)的狀態(tài)..
使用頭插會改變鏈表的上的順序扶认,但是如果使用尾插侨拦,在擴容時會保持鏈表元素原本的順序,就不會出現(xiàn)鏈表成環(huán)的問題了
Java8在同樣的前提下并不會引起死循環(huán)辐宾,原因是擴容轉(zhuǎn)移后前后鏈表順序不變狱从,保持之前節(jié)點的引用關(guān)系。
那是不是意味著Java8就可以把HashMap用在多線程中呢叠纹?
那是必然不可以的,HashMap put/get方法都沒有加同步鎖季研,這里存在一個并發(fā)修改的問題,ConcurrentModifyExcption,所以線程安全還是無法保證誉察。
二 .那我問你HashMap的默認(rèn)初始化長度是多少与涡?16,為啥是16呢?
為了能讓 HashMap 存取高效,盡量較少碰撞,也就是要盡量把數(shù)據(jù)分配均勻驼卖。我們上面也講到了過了氨肌,Hash 值的范圍值-2147483648到2147483647,前后加起來大概40億的映射空間酌畜,只要哈希函數(shù)映射得比較均勻松散怎囚,一般應(yīng)用是很難出現(xiàn)碰撞的。但問題是一個40億長度的數(shù)組桥胞,內(nèi)存是放不下的恳守。所以這個散列值是不能直接拿來用的。用之前還要先做對數(shù)組的長度取模運算埠戳,得到的余數(shù)才能用來要存放的位置也就是對應(yīng)的數(shù)組下標(biāo)井誉。這個數(shù)組下標(biāo)的計算方法是“ (n - 1) & hash ”。(n代表數(shù)組長度)整胃。這也就解釋了 HashMap 的長度為什么是2的冪次方。
這個算法應(yīng)該如何設(shè)計呢喳钟?
我們首先可能會想到采用%取余的操作來實現(xiàn)屁使。但是,
(也就是說 hash%length==hash&(length-1)的前提是 length 是2的 n 次方奔则;)蛮寂。”
詳細(xì)請看
至于為啥初始長度是16我覺得就是大家都覺得16通常情況夠用了吧.如果你有其他看法可以評論
三 .為啥我們重寫equals方法的時候需要重寫hashCode方法呢?
因為在java中抽莱,所有的對象都是繼承于Object類范抓。
Ojbect類中有兩個方法equals、hashCode食铐,這兩個方法都是用來比較兩個對象是否相等的匕垫。
在未重寫equals方法我們是繼承了object的equals方法,那里的 equals是比較兩個對象的內(nèi)存地址虐呻,顯然我們new了2個對象內(nèi)存地址肯定不一樣
對于值對象象泵,==比較的是兩個對象的值
對于引用對象,比較的是兩個對象的地址
所以如果我們對equals方法進行了重寫斟叼,建議一定要對hashCode方法重寫偶惠,以保證相同的對象返回相同的hash值,不同的對象返回不同的hash值朗涩。
不然一個鏈表的對象忽孽,你哪里知道你要找的是哪個,到時候發(fā)現(xiàn)hashCode都一樣,這不是完犢子嘛扒腕。
關(guān)于本文中頭插法尾插法詳情可看碼農(nóng)屆網(wǎng)紅敖丙的原文https://juejin.im/user/59b416065188257e671b670a/posts
但是我覺得這篇文章寫的比較簡略,面向面試還行,如果要了解基本原理建議大家可以看看https://blog.csdn.net/thqtzq/article/details/90485663