摘要:對(duì),分別對(duì)和進(jìn)行排序。主要保存對(duì)象的信息,主要是方法。組件主要是通過對(duì)進(jìn)行緩存。同步控制中是一個(gè)靜變量,那么隨之而來的就是的同步問題。現(xiàn)在的問題在于如果獲取不了對(duì)象時(shí)會(huì)要執(zhí)行設(shè)置操作操作,此時(shí)并發(fā)問題隨之而來。
一.hashmap的底層原理。
1.hashmap的數(shù)據(jù)結(jié)構(gòu)
Hashmap實(shí)際上是一個(gè)數(shù)組和鏈表的結(jié)合體(在數(shù)據(jù)結(jié)構(gòu)中,一般稱之為“鏈表散列“),請(qǐng)看下圖(橫排表示數(shù)組,縱排表示數(shù)組元素【實(shí)際上是一個(gè)鏈表】)。
從圖中我們可以看到一個(gè)hashmap就是一個(gè)數(shù)組結(jié)構(gòu),當(dāng)新建一個(gè)hashmap的時(shí)候,就會(huì)初始化一個(gè)數(shù)組。
上面的Entry就是數(shù)組中的元素,它持有一個(gè)指向下一個(gè)元素的引用,這就構(gòu)成了鏈表。
當(dāng)我們往hashmap中put元素的時(shí)候,先根據(jù)key的hash值得到這個(gè)元素在數(shù)組中的位置(即下標(biāo)),然后就可以把這個(gè)元素放到對(duì)應(yīng)的位置中了。如果這個(gè)元素所在的位子上已經(jīng)存放有其他元素了,那么在同一個(gè)位子上的元素將以鏈表的形式存放,新加入的放在鏈頭,最先加入的放在鏈尾。從hashmap中g(shù)et元素時(shí),首先計(jì)算key的hashcode,找到數(shù)組中對(duì)應(yīng)位置的某一元素,然后通過key的equals方法在對(duì)應(yīng)位置的鏈表中找到需要的元素。從這里我們可以想象得到,如果每個(gè)位置上的鏈表只有一個(gè)元素,那么hashmap的get效率將是最高的.
2.hash算法
我們可以看到在hashmap中要找到某個(gè)元素,需要根據(jù)key的hash值來求得對(duì)應(yīng)數(shù)組中的位置。如何計(jì)算這個(gè)位置就是hash算法。前面說過hashmap的數(shù)據(jù)結(jié)構(gòu)是數(shù)組和鏈表的結(jié)合,所以我們當(dāng)然希望這個(gè)hashmap里面的元素位置盡量的分布均勻些,盡量使得每個(gè)位置上的元素?cái)?shù)量只有一個(gè),那么當(dāng)我們用hash算法求得這個(gè)位置的時(shí)候,馬上就可以知道對(duì)應(yīng)位置的元素就是我們要的,而不用再去遍歷鏈表。
首先算得key得hashcode值,然后跟數(shù)組的長(zhǎng)度-1做一次“與”運(yùn)算(&)。看上去很簡(jiǎn)單,其實(shí)比較有玄機(jī)。比如數(shù)組的長(zhǎng)度是2的4次方,那么hashcode就會(huì)和2的4次方-1做“與”運(yùn)算。很多人都有這個(gè)疑問,為什么hashmap的數(shù)組初始化大小都是2的次方大小時(shí),hashmap的效率最高,我以2的4次方舉例,來解釋一下為什么數(shù)組大小為2的冪時(shí)hashmap訪問的性能最高。
看下圖,左邊兩組是數(shù)組長(zhǎng)度為16(2的4次方),右邊兩組是數(shù)組長(zhǎng)度為15。兩組的hashcode均為8和9,但是很明顯,當(dāng)它們和1110“與”的時(shí)候,產(chǎn)生了相同的結(jié)果,也就是說它們會(huì)定位到數(shù)組中的同一個(gè)位置上去,這就產(chǎn)生了碰撞,8和9會(huì)被放到同一個(gè)鏈表上,那么查詢的時(shí)候就需要遍歷這個(gè)鏈表,得到8或者9,這樣就降低了查詢的效率。同時(shí),我們也可以發(fā)現(xiàn),當(dāng)數(shù)組長(zhǎng)度為15的時(shí)候,hashcode的值會(huì)與14(1110)進(jìn)行“與”,那么最后一位永遠(yuǎn)是0,而0001,0011,0101,1001,1011,0111,1101這幾個(gè)位置永遠(yuǎn)都不能存放元素了,空間浪費(fèi)相當(dāng)大,更糟的是這種情況中,數(shù)組可以使用的位置比數(shù)組長(zhǎng)度小了很多,這意味著進(jìn)一步增加了碰撞的幾率,減慢了查詢的效率!
所以說,當(dāng)數(shù)組長(zhǎng)度為2的n次冪的時(shí)候,不同的key算得得index相同的幾率較小,那么數(shù)據(jù)在數(shù)組上分布就比較均勻,也就是說碰撞的幾率小,相對(duì)的,查詢的時(shí)候就不用遍歷某個(gè)位置上的鏈表,這樣查詢效率也就較高了。所以,在存儲(chǔ)大容量數(shù)據(jù)的時(shí)候,最好預(yù)先指定hashmap的size為2的整數(shù)次冪次方。就算不指定的話,也會(huì)以大于且最接近指定值大小的2次冪來初始化的。
3、hashmap的resize
那么hashmap什么時(shí)候進(jìn)行擴(kuò)容呢?當(dāng)hashmap中的元素個(gè)數(shù)超過數(shù)組大小loadFactor時(shí),就會(huì)進(jìn)行數(shù)組擴(kuò)容,loadFactor的默認(rèn)值為0.75,也就是說,默認(rèn)情況下,數(shù)組大小為16,那么當(dāng)hashmap中元素個(gè)數(shù)超過160.75=12的時(shí)候,就把數(shù)組的大小擴(kuò)展為216=32,即擴(kuò)大一倍,然后重新計(jì)算每個(gè)元素在數(shù)組中的位置,而這是一個(gè)非常消耗性能的操作,所以如果我們已經(jīng)預(yù)知hashmap中元素的個(gè)數(shù),那么預(yù)設(shè)元素的個(gè)數(shù)能夠有效的提高h(yuǎn)ashmap的性能。比如說,我們有1000個(gè)元素new HashMap(1000), 但是理論上來講new HashMap(1024)更合適,不過上面annegu已經(jīng)說過,即使是1000,hashmap也自動(dòng)會(huì)將其設(shè)置為1024。 但是new HashMap(1024)還不是更合適的,因?yàn)?.751000 < 1000, 也就是說為了讓0.75 * size >1000, 我們必須這樣new HashMap(2048)才最合適,既考慮了&的問題,也避免了resize的問題。
4、key的hashcode與equals方法改寫
在第一部分hashmap的數(shù)據(jù)結(jié)構(gòu)中,annegu就寫了get方法的過程:首先計(jì)算key的hashcode,找到數(shù)組中對(duì)應(yīng)位置的某一元素,然后通過key的equals方法在對(duì)應(yīng)位置的鏈表中找到需要的元素。所以,hashcode與equals方法對(duì)于找到對(duì)應(yīng)元素是兩個(gè)關(guān)鍵方法。
Hashmap的key可以是任何類型的對(duì)象,例如User這種對(duì)象,為了保證兩個(gè)具有相同屬性的user的hashcode相同,我們就需要改寫hashcode方法,比方把hashcode值的計(jì)算與User對(duì)象的id關(guān)聯(lián)起來,那么只要user對(duì)象擁有相同id,那么他們的hashcode也能保持一致了,這樣就可以找到在hashmap數(shù)組中的位置了。如果這個(gè)位置上有多個(gè)元素,還需要用key的equals方法在對(duì)應(yīng)位置的鏈表中找到需要的元素,所以只改寫了hashcode方法是不夠的,equals方法也是需要改寫滴~當(dāng)然啦,按正常思維邏輯,equals方法一般都會(huì)根據(jù)實(shí)際的業(yè)務(wù)內(nèi)容來定義,例如根據(jù)user對(duì)象的id來判斷兩個(gè)user是否相等。
在改寫equals方法的時(shí)候,需要滿足以下三點(diǎn):
(1) 自反性:就是說a.equals(a)必須為true。
(2) 對(duì)稱性:就是說a.equals(b)=true的話,b.equals(a)也必須為true。
(3) 傳遞性:就是說a.equals(b)=true,并且b.equals(c)=true的話,a.equals(c)也必須為true。
通過改寫key對(duì)象的equals和hashcode方法,我們可以將任意的業(yè)務(wù)對(duì)象作為map的key(前提是你確實(shí)有這樣的需要)。
摘自:http://blog.csdn.net/jdjdndhj...
http://www.zhangxinxu.com/wor...
這個(gè)寫的還是很到位的,大體瀏覽了一下,沒太仔細(xì)看,掌握一些大概,以后有空再完全理解。
通過緩存來優(yōu)化
需要兩個(gè)組件ClassInfo和ReflectionCache。
ClassInfo主要保存Class對(duì)象的信息,主要是方法Map。其中ClassInfo中包括三部分方法的Map: Getter, Setter, Other。Getter是Class的屬性的獲取方法,Setter是Class的屬性的設(shè)置方法,Other是其它方法。需要注意的是Getter和Setter的方法需要完全符合Javabean規(guī)范(isXXX方法屬于Getter方法范圍內(nèi)),其key值是方法對(duì)應(yīng)的屬性名。Other方法是除Getter和Setter以外的其它方法。
ReflectionCache組件主要是通過HashMap對(duì)ClassInfo進(jìn)行緩存。緩存的鍵值是ClassInfo中Class對(duì)象的全稱。如一個(gè)String對(duì)象,它緩存的鍵值就是java.lang.String。并且ReflectionCache提供了幾種不同get和put方法來方便用戶的操作。
另外ClassInfo的生成需要用到ClassInfoUtils工具。它的主要工作是創(chuàng)建ClassInfo對(duì)象,其中創(chuàng)建ClassInfo時(shí)可以提供Method Type信息來指定緩存的方法類型(如:所有方法-All、存取器方法-Access、獲取方法-Getter和設(shè)置方法-Setter)。
5.同步控制
ReflectionCache中ClassInfoMap是一個(gè)靜變量,那么隨之而來的就是HashMap的同步問題。我對(duì)ReflectionCache的做了些改進(jìn),主要是對(duì)put方法的處理。首先HashMap的獲取操作(get操作)沒有加入同步操作,因此獲取的操作是可以并發(fā)的。現(xiàn)在的問題在于如果獲取不了ClassInfo對(duì)象時(shí)會(huì)要執(zhí)行設(shè)置操作(set操作),此時(shí)并發(fā)問題隨之而來。可能在同一時(shí)刻會(huì)有很多線程去設(shè)置ClassInfo,在第一個(gè)設(shè)置完ClassInfo的線程結(jié)束后,第二個(gè)線程應(yīng)該停止設(shè)置ClassInfo。在此需求之上,我們需要對(duì)ReflectionCache的put操作上加上同步塊,并且讓put操作再執(zhí)行一個(gè)額外的操作:返回添加到ClassInfoMap中的ClassInfo,不管它是不是其它線程添加的。因此我們?cè)谠O(shè)置ClassInfo時(shí),可以這樣操作:
ClassInfo classInfo = ReflectionCache.putClassInfo(String.class);
select f1 from (select f1 from t1 UNION all select f2 from t2) t3 GROUP BY f1 HAVING COUNT(f1) = 113.hibernate的一二級(jí)緩存 14.session和cookie的區(qū)別與聯(lián)系 15.springboot是如何實(shí)現(xiàn),沒有配置文件的。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/68671.html
摘要:收集的一些前端面試題從面試題發(fā)現(xiàn)不足,進(jìn)而查漏補(bǔ)缺,比通過面試更難得及各大互聯(lián)網(wǎng)公司前端筆試面試題篇及各大互聯(lián)網(wǎng)公司前端筆試面試題篇面試題個(gè)和個(gè)經(jīng)典面試題前端開發(fā)面試題如何面試前端工程師很重要個(gè)變態(tài)題解析如何通過餓了么面試輕 收集的一些前端面試題 從面試題發(fā)現(xiàn)不足,進(jìn)而查漏補(bǔ)缺,比通過面試更難得 1 BAT及各大互聯(lián)網(wǎng)公司2014前端筆試面試題--Html,Css篇 2 BAT...
摘要:收集的一些前端面試題從面試題發(fā)現(xiàn)不足,進(jìn)而查漏補(bǔ)缺,比通過面試更難得及各大互聯(lián)網(wǎng)公司前端筆試面試題篇及各大互聯(lián)網(wǎng)公司前端筆試面試題篇面試題個(gè)和個(gè)經(jīng)典面試題前端開發(fā)面試題如何面試前端工程師很重要個(gè)變態(tài)題解析如何通過餓了么面試輕 收集的一些前端面試題 從面試題發(fā)現(xiàn)不足,進(jìn)而查漏補(bǔ)缺,比通過面試更難得 1 BAT及各大互聯(lián)網(wǎng)公司2014前端筆試面試題--Html,Css篇 2 BAT...
摘要:需求一個(gè)輸入框,用戶輸入時(shí)有聯(lián)想搜索,每次用戶輸入都會(huì)觸發(fā)請(qǐng)求,過多的請(qǐng)求會(huì)造成服務(wù)器的壓力,如何去解決這個(gè)問題請(qǐng)求函數(shù)面試者延遲發(fā)送可以去解決這樣的問題。 寫在前面的話 一般來說,面試質(zhì)量的高低很大程度影響公司是否想接受改人才,也影響了人才是否愿意去公司。質(zhì)量高的面試,公司能表明對(duì)人才的要求,個(gè)人也能表明所期待的公司是一個(gè)什么模式的公司。最終會(huì)有利于雙向選擇的過程。能盡早的把問題暴露...
摘要:手冊(cè)網(wǎng)超級(jí)有用的前端基礎(chǔ)技術(shù)面試問題收集前端面試題目及答案匯總史上最全前端面試題含答案常見前端面試題及答案經(jīng)典面試題及答案精選總結(jié)前端面試過程中最容易出現(xiàn)的問題前端面試題整理騰訊前端面試經(jīng)驗(yàn)前端基礎(chǔ)面試題部分最新前端面試題攻略前端面試前端入 手冊(cè)網(wǎng):http://www.shouce.ren/post/index 超級(jí)有用的前端基礎(chǔ)技術(shù)面試問題收集:http://www.codec...
摘要:手冊(cè)網(wǎng)超級(jí)有用的前端基礎(chǔ)技術(shù)面試問題收集前端面試題目及答案匯總史上最全前端面試題含答案常見前端面試題及答案經(jīng)典面試題及答案精選總結(jié)前端面試過程中最容易出現(xiàn)的問題前端面試題整理騰訊前端面試經(jīng)驗(yàn)前端基礎(chǔ)面試題部分最新前端面試題攻略前端面試前端入 手冊(cè)網(wǎng):http://www.shouce.ren/post/index 超級(jí)有用的前端基礎(chǔ)技術(shù)面試問題收集:http://www.codec...
閱讀 2604·2021-11-02 14:39
閱讀 4322·2021-10-11 10:58
閱讀 1446·2021-09-06 15:12
閱讀 1837·2021-09-01 10:49
閱讀 1326·2019-08-29 18:31
閱讀 1882·2019-08-29 16:10
閱讀 3331·2019-08-28 18:21
閱讀 867·2019-08-26 10:42