HashMap底層實(shí)現(xiàn)原理_第1頁
HashMap底層實(shí)現(xiàn)原理_第2頁
HashMap底層實(shí)現(xiàn)原理_第3頁
HashMap底層實(shí)現(xiàn)原理_第4頁
HashMap底層實(shí)現(xiàn)原理_第5頁
已閱讀5頁,還剩2頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

HashMap底層實(shí)現(xiàn)原理/HashMap與HashTable區(qū)別/HashMap與HashSet區(qū)別HashMap的工作原理HashMap基于hashing原理,我們通過put()和get()方法儲(chǔ)存和獲取對(duì)象。當(dāng)我們將鍵值對(duì)傳遞給put()方法時(shí),它調(diào)用鍵對(duì)象的hashCode()方法來計(jì)算hashcode,讓后找到bucket位置來儲(chǔ)存值對(duì)象。當(dāng)獲取對(duì)象時(shí),通過鍵對(duì)象的equals()方法找到正確的鍵值對(duì),然后返回值對(duì)象。HashMap使用鏈表來解決碰撞問題,當(dāng)發(fā)生碰撞了,對(duì)象將會(huì)儲(chǔ)存在鏈表的下一個(gè)節(jié)點(diǎn)中。HashMap在每個(gè)鏈表節(jié)點(diǎn)中儲(chǔ)存鍵值對(duì)對(duì)象。當(dāng)兩個(gè)不同的鍵對(duì)象的hashcode相同時(shí)會(huì)發(fā)生什么?它們會(huì)儲(chǔ)存在同一個(gè)bucket位置的鏈表中。鍵對(duì)象的equals()方法用來找到鍵值對(duì)。因?yàn)镠ashMap的好處非常多,我曾經(jīng)在電子商務(wù)的應(yīng)用中使用HashMap作為緩存。因?yàn)榻鹑陬I(lǐng)域非常多的運(yùn)用Java,也出于性能的考慮,我們會(huì)經(jīng)常用到HashMap和ConcurrentHashMap。HashMap和Hashtable的區(qū)別HashMap和Hashtable都實(shí)現(xiàn)了Map接口,但決定用哪一個(gè)之前先要弄清楚它們之間的分別。主要的區(qū)別有:線程安全性,同步(synchronization),以及速度。HashMap幾乎可以等價(jià)于Hashtable,除了HashMap是非synchronized的,并可以接受null(HashMap可以接受為null的鍵值(key)和值(value),而Hashtable則不行)。HashMap是非synchronized,而Hashtable是synchronized,這意味著Hashtable是線程安全的,多個(gè)線程可以共享一個(gè)Hashtable;而如果沒有正確的同步的話,多個(gè)線程是不能共享HashMap的。Java5提供了ConcurrentHashMap,它是HashTable的替代,比HashTable的擴(kuò)展性更好。另一個(gè)區(qū)別是HashMap的迭代器(Iterator)是fail-fast迭代器,而Hashtable的enumerator迭代器不是fail-fast的。所以當(dāng)有其它線程改變了HashMap的結(jié)構(gòu)(增加或者移除元素),將會(huì)拋出ConcurrentModificationException,但迭代器本身的remove()方法移除元素則不會(huì)拋出ConcurrentModificationException異常。但這并不是一個(gè)一定發(fā)生的行為,要看JVM。這條同樣也是Enumeration和Iterator的區(qū)別。由于Hashtable是線程安全的也是synchronized,所以在單線程環(huán)境下它比HashMap要慢。如果你不需要同步,只需要單一線程,那么使用HashMap性能要好過Hashtable。HashMap不能保證隨著時(shí)間的推移Map中的元素次序是不變的。要注意的一些重要術(shù)語:sychronized意味著在一次僅有一個(gè)線程能夠更改Hashtable。就是說任何線程要更新Hashtable時(shí)要首先獲得同步鎖,其它線程要等到同步鎖被釋放之后才能再次獲得同步鎖更新Hashtable。Fail-safe和iterator迭代器相關(guān)。如果某個(gè)集合對(duì)象創(chuàng)建了Iterator或者Listiterator,然后其它的線程試圖“結(jié)構(gòu)上”更改集合對(duì)象,將會(huì)拋出ConcurrentModificationException異常。但其它線程可以通過set()方法更改集合對(duì)象是允許的,因?yàn)檫@并沒有從“結(jié)構(gòu)上”更改集合。但是假如已經(jīng)從結(jié)構(gòu)上進(jìn)行了更改,再調(diào)用set()方法,將會(huì)拋出lllegalArgumentException異常。結(jié)構(gòu)上的更改指的是刪除或者插入一個(gè)元素,這樣會(huì)影響到map的結(jié)構(gòu)。我們能否讓HashMap同步?HashMap可以通過下面的語句進(jìn)行同步:Mapm=Collections.synchronizeMap(hashMap);結(jié)論Hashtable和HashMap有幾個(gè)主要的不同:線程安全以及速度。僅在你需要完全的線程安全的時(shí)候使用Hashtable,而如果你使用Java5或以上的話,請(qǐng)使用ConcurrentHashMap吧。hashMap和HashSet的區(qū)別是Java面試中最常被問到的問題。如果沒有涉及到Collection框架以及多線程的面試,可以說是不完整。而Collection框架的問題不涉及到HashSet和HashMap,也可以說是不完整。HashMap和HashSet都是collection框架的一部分,它們讓我們能夠使用對(duì)象的集合。collection框架有自己的接口和實(shí)現(xiàn),主要分為Set接口,List接口和Queue接口。它們有各自的特點(diǎn),Set的集合里不允許對(duì)象有重復(fù)的值,List允許有重復(fù),它對(duì)集合中的對(duì)象進(jìn)行索引,Queue的工作原理是FCFS算法(FirstCome,FirstServe)。首先讓我們來看看什么是HashMap和HashSet,然后再來比較它們之間的分別。HashMap和HashSet的區(qū)別HashMap和HashSet的區(qū)別是Java面試中最常被問到的問題。如果沒有涉及到Collection框架以及多線程的面試,可以說是不完整。而Collection框架的問題不涉及到HashSet和HashMap,也可以說是不完整。HashMap和HashSet都是collection框架的一部分,它們讓我們能夠使用對(duì)象的集合。collection框架有自

己的接口和實(shí)現(xiàn),主要分為Set接口,List接口和Queue接口。它們有各自的特點(diǎn),Set的集合里不允許對(duì)象有重復(fù)的值,List允許有重復(fù),它對(duì)集合中的對(duì)象進(jìn)行索引,Queue的工作原理是FCFS算法(FirstCome,FirstServe)。首先讓我們來看看什么是HashMap和HashSet,然后再來比較它們之間的分別。什么是HashSetHashSet實(shí)現(xiàn)了Set接口,它不允許集合中有重復(fù)的值,當(dāng)我們提到HashSet時(shí),第一件事情就是在將對(duì)象存儲(chǔ)在HashSet之前,要先確保對(duì)象重寫equals()和hashCode()方法,這樣才能比較對(duì)象的值是否相等,以確保set中沒有儲(chǔ)存相等的對(duì)象。如果我們沒有重寫這兩個(gè)方法,將會(huì)使用這個(gè)方法的默認(rèn)實(shí)現(xiàn)。publicbooleanadd(Objecto)方法用來在Set中添加元素,當(dāng)元素值重復(fù)時(shí)則會(huì)立即返回false,如果成功添加的話會(huì)返回true。什么是HashMapHashMap實(shí)現(xiàn)了Map接口,Map接口對(duì)鍵值對(duì)進(jìn)行映射。Map中不允許重復(fù)的鍵。Map接口有兩個(gè)基本的實(shí)現(xiàn),HashMap和TreeMap。TreeMap保存了對(duì)象的排列次序,而HashMap則不能。HashMap允許鍵和值為null。HashMap是非synchronized的,但collection框架提供方法能保證HashMapsynchronized,這樣多個(gè)線程同時(shí)訪問HashMap時(shí),能保證只有一個(gè)線程更改Map。publicObjectput(ObjectKey,Objectvalue)方法用來將元素添加到map中。HashSet和HashMap的區(qū)別*HashMap**HashSet**HashMap**HashSet*HashMap儲(chǔ)存鍵值對(duì)使用HashMap儲(chǔ)存鍵值對(duì)使用put()方法將元素放入map中HashMap中使用鍵對(duì)象來計(jì)算hashcode值口ShMap實(shí)現(xiàn)了Map接HashSet實(shí)現(xiàn)了Set接口I 1HashSet僅僅存儲(chǔ)對(duì)象使用add()方法將元素放入set中HashSet使用成員對(duì)象來計(jì)算hashcode值,對(duì)于兩個(gè)對(duì)象來說hashcode可能相同,所以equals()方法用來判斷對(duì)象的相等性,如果兩個(gè)對(duì)象不同的話,那么返回falseHashMap比較快,因?yàn)槭鞘褂梦ㄒ坏逆I來獲HashSet較HashMap來說比較慢取對(duì)象面試題HashMap的工作原理是近年來常見的Java面試題。幾乎每個(gè)Java程序員都知道HashMap,都知道哪里要用HashMap,知道Hashtable和HashMap之間的區(qū)別,那么為何這道面試題如此特殊呢?是因?yàn)檫@道題考察的深度很深。這題經(jīng)常出現(xiàn)在高級(jí)或中高級(jí)面試中。投資銀行更喜歡問這個(gè)問題,甚至?xí)竽銓?shí)現(xiàn)HashMap來考察你的編程能力。ConcurrentHashMap和其它同步集合的引入讓這道題變得更加復(fù)雜。讓我們開始探索的旅程吧!“你用過HashMap嗎?”“什么是HashMap?你為什么用到它?”幾乎每個(gè)人都會(huì)回答"是的”,然后回答HashMap的一些特性,譬如HashMap可以接受null鍵值和值,而Hashtable則不能;HashMap是非synchronized;HashMap很快;以及HashMap儲(chǔ)存的是鍵值對(duì)等等。這顯示出你已經(jīng)用過HashMap,而且對(duì)它相當(dāng)?shù)氖煜?。但是面試官來個(gè)急轉(zhuǎn)直下,從此刻開始問出一些刁鉆的問題,關(guān)于HashMap的更多基礎(chǔ)的細(xì)節(jié)。面試官可能會(huì)問出下面的問題:“你知道HashMap的工作原理嗎?”“你知道HashMap的get()方法的工作原理嗎?”你也許會(huì)回答“我沒有詳查標(biāo)準(zhǔn)的JavaAPI,你可以看看Java源代碼或者OpenJDK?!薄拔铱梢杂肎oogle找到答案?!钡恍┟嬖囌呖赡芸梢越o出答案,“HashMap是基于hashing的原理,我們使用put(key,value)存儲(chǔ)對(duì)象到HashMap中,使用get(key)從HashMap中獲取對(duì)象。當(dāng)我們給put()方法傳遞鍵和值時(shí),我們先對(duì)鍵調(diào)用hashCode()方法,返回的hashCode用于找到bucket位置來儲(chǔ)存Entry對(duì)象。"這里關(guān)鍵點(diǎn)在于指出,HashMap是在bucket中儲(chǔ)存鍵對(duì)象和值對(duì)象,作為Map.Entry。這一點(diǎn)有助于理解獲取對(duì)象的邏輯。如果你沒有意識(shí)到這一點(diǎn),或者錯(cuò)誤的認(rèn)為僅僅只在bucket中存儲(chǔ)值的話,你將不會(huì)回答如何從HashMap中獲取對(duì)象的邏輯。這個(gè)答案相當(dāng)?shù)恼_,也顯示出面試者確實(shí)知道hashing以及HashMap的工作原理。但是這僅僅是故事的開始,當(dāng)面試官加入一些Java程序員每天要碰到的實(shí)際場(chǎng)景的時(shí)候,錯(cuò)誤的答案頻現(xiàn)。下個(gè)問題可能是關(guān)于HashMap中的碰撞探測(cè)(collisiondetection)以及碰撞的解決方法:“當(dāng)兩個(gè)對(duì)象的hashcode相同會(huì)發(fā)生什么?”從這里開始,真正的困惑開始了,一些面試者會(huì)回答因?yàn)閔ashcode相同,所以兩個(gè)對(duì)象是相等的,HashMap將會(huì)拋出異常,或者不會(huì)存儲(chǔ)它們。然后面試官可能會(huì)提醒他們有equals()和hashCode()兩個(gè)方法,并告訴他們兩個(gè)對(duì)象就算hashcode相同,但是它們可能并不相等。一些面試者可能就此放棄,而另外一些還能繼續(xù)挺進(jìn),他們回答“因?yàn)閔ashcode相同,所以它們的bucket位置相同,‘碰撞'會(huì)發(fā)生。因?yàn)镠ashMap使用鏈表存儲(chǔ)對(duì)象,這個(gè)Entry(包含有鍵值對(duì)的Map.Entry對(duì)象)會(huì)存儲(chǔ)在鏈表中。”這個(gè)答案非常的合理,雖然有很多種處理碰撞的方法,這種方法是最簡(jiǎn)單的,也正是HashMap的處理方法。但故事還沒有完結(jié),面試官會(huì)繼續(xù)問:“如果兩個(gè)鍵的hashcode相同,你如何獲取值對(duì)象?”面試者會(huì)回答:當(dāng)我們調(diào)用get()方法,HashMap會(huì)使用鍵對(duì)象的hashcode找到bucket位置,然后獲取值對(duì)象。面試官提醒他如果有兩個(gè)值對(duì)象儲(chǔ)存在同一個(gè)bucket,他給出答案:將會(huì)遍歷鏈表直到找到值對(duì)象。面試官會(huì)問因?yàn)槟悴]有值對(duì)象去比較,你是如何確定確定找到值對(duì)象的?除非面試者直到HashMap在鏈表中存儲(chǔ)的是鍵值對(duì),否則他們不可能回答出這一題。其中一些記得這個(gè)重要知識(shí)點(diǎn)的面試者會(huì)說,找到bucket位置之后,會(huì)調(diào)用keys.equals()方法去找到鏈表中正確的節(jié)點(diǎn),最終找到要找的值對(duì)象。完美的答案!許多情況下,面試者會(huì)在這個(gè)環(huán)節(jié)中出錯(cuò),因?yàn)樗麄兓煜薶ashCode()和equals。方法。因?yàn)樵诖酥癶ashCode()屢屢出現(xiàn),而equals()方法僅僅在獲取值對(duì)象的時(shí)候才出現(xiàn)。一些優(yōu)秀的開發(fā)者會(huì)指出使用不可變的、聲明作final的對(duì)象,并且采用合適的equals()和hashCode()方法的話,將會(huì)減少碰撞的發(fā)生,提高效率。不可變性使得能夠緩存不同鍵的hashcode,這將提高整個(gè)獲取對(duì)象的速度,使用String,Interger這樣的wrapper類作為鍵是非常好的選擇。如果你認(rèn)為到這里已經(jīng)完結(jié)了,那么聽到下面這個(gè)問題的時(shí)候,你會(huì)大吃一驚?!叭绻鸋ashMap的大小超過了負(fù)載因子(loadfactor)定義的容量,怎么辦?”除非你真正知道HashMap的工作原理,否則你將回答不出這道題。默認(rèn)的負(fù)載因子大小為0.75,也就是說,當(dāng)一個(gè)map填滿了75%的bucket時(shí)候,和其它集合類(如ArrayList等)一樣,將會(huì)創(chuàng)建原來HashMap大小的兩倍的bucket數(shù)組,來重新調(diào)整map的大小,并將原來的對(duì)象放入新的bucket數(shù)組中。這個(gè)過程叫作rehashing,因?yàn)樗{(diào)用hash方法找到新的bucket位置。如果你能夠回答這道問題,下面的問題來了:“你了解重新調(diào)整HashMap大小存在什么問題嗎?”你可能回答不上來,這時(shí)面試官會(huì)提醒你當(dāng)多線程的情況下,可能產(chǎn)生條件競(jìng)爭(zhēng)(racecondition)。當(dāng)重新調(diào)整HashMap大小的時(shí)候,確實(shí)存在條件競(jìng)爭(zhēng),因?yàn)槿绻麅蓚€(gè)線程都發(fā)現(xiàn)HashMap需要重新調(diào)整大小了,它們會(huì)同時(shí)試著調(diào)整大小。在調(diào)整大小的過程中,存儲(chǔ)在鏈表中的元素的次序會(huì)反過來,因?yàn)橐苿?dòng)到新的bucket位置的時(shí)候,HashMap并不會(huì)將元素放在鏈表的尾部,而是放在頭部,這是為了避免尾部遍歷(tailtraversing)。如果條件競(jìng)爭(zhēng)發(fā)生了,那么就死循環(huán)了。這個(gè)時(shí)候,你可以質(zhì)問面試官,為什么這么奇怪,要在多線程的環(huán)境下使用HashMap呢?:)熱心的讀者貢獻(xiàn)了更多的關(guān)于HashMap的問題:1.為什么String,Interger這樣的wrapper類適合作為鍵?String,Interger這樣的wrapper類作為HashMap的鍵是再適合不過了,而且String最為常用。因?yàn)镾tring是不可變的,也是final的,而且已經(jīng)重寫了equals()和hashCode()方法了。其他的wrapper類也有這個(gè)特點(diǎn)。不可變性是必要的,因?yàn)闉榱艘?jì)算hashCode(),就要防止鍵值改變,如果鍵值在放入時(shí)和獲取時(shí)返回不同的hashcode的話,那么就不能從HashMap中找到你想要的對(duì)象。不可變性還有其他的優(yōu)點(diǎn)如線程安全。如果你可以僅僅通過將某個(gè)fiel

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

評(píng)論

0/150

提交評(píng)論