




下載本文檔
版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡介
1、HashMap的底層實(shí)現(xiàn)原理一、HashMap的數(shù)據(jù)結(jié)構(gòu)總述:哈希的出現(xiàn)時(shí)因?yàn)閭鹘y(tǒng)數(shù)據(jù)結(jié)構(gòu)如線性表(數(shù)組,鏈表等),樹中,關(guān)鍵字與其它的存放位置不存在對應(yīng)的關(guān)系。因此在查找關(guān)鍵字的時(shí)候需要逐個(gè)比對,雖然出現(xiàn)了二分查找等各種提高效率的的查找算法。但是這些并不足夠,希望在查詢關(guān)鍵字的時(shí)候不經(jīng)過任何比較,一次存取便能得到所查記錄。因此,我們必須在關(guān)鍵字和其對應(yīng)的存儲位置間建立對應(yīng)的關(guān)系f。這種對應(yīng)的關(guān)系f被稱為哈希函數(shù),按此思想建立的表為哈希表。關(guān)鍵在于哈希函數(shù)如何構(gòu)造。意思就是:關(guān)鍵字的存儲位置是有關(guān)鍵字的內(nèi)容決定的。數(shù)據(jù)結(jié)構(gòu)中有數(shù)組和鏈表來實(shí)現(xiàn)對數(shù)據(jù)的存儲,但這兩者基本上是兩個(gè)極端。數(shù)組:數(shù)組存
2、儲區(qū)間是連續(xù)的,占用內(nèi)存嚴(yán)重,故空間復(fù)雜的很大。但數(shù)組的二分查找時(shí)間復(fù)雜度小,為O(1);數(shù)組的特點(diǎn)是:尋址容易,插入和刪除困難;鏈表:鏈表存儲區(qū)間離散,占用內(nèi)存比較寬松,故空間復(fù)雜度很小,但時(shí)間復(fù)雜度很大,達(dá)O(N)。鏈表的特點(diǎn)是:尋址困難,插入和刪除容易。哈希表:那么我們能不能綜合兩者的特性,做出一種尋址容易,插入刪除也容易的數(shù)據(jù)結(jié)構(gòu)?答案是肯定的,這就是我們要提起的哈希表。哈希表((Hash table)既滿足了數(shù)據(jù)的查找方便,同時(shí)不占用太多的內(nèi)容空間,使用也十分方便。哈希表有多種不同的實(shí)現(xiàn)方法,我接下來解釋的是最常用的一種方法拉鏈法,我們可以理解為“鏈表的數(shù)組”一個(gè)長度為16的數(shù)組中,
3、每個(gè)元素存儲的是一個(gè)鏈表的頭結(jié)點(diǎn)。那么這些元素是按照什么樣的規(guī)則存儲到數(shù)組中呢。一般情況是通過hash(key)&len-1獲得,也就是元素的key的哈希值對數(shù)組長度取模得到。HashMap其實(shí)也是一個(gè)線性的數(shù)組實(shí)現(xiàn)的,所以可以理解為其存儲數(shù)據(jù)的容器就是一個(gè)線性數(shù)組。這可能讓我們很不解,一個(gè)線性的數(shù)組怎么實(shí)現(xiàn)按鍵值對來存取數(shù)據(jù)呢?這里HashMap有做一些處理。首先HashMap里面實(shí)現(xiàn)一個(gè)靜態(tài)內(nèi)部類Entry,其重要的屬性有key , value, next,從屬性key,value我們就能很明顯的看出來Entry就是HashMap鍵值對實(shí)現(xiàn)的一個(gè)基礎(chǔ)bean,我們上面說到HashMap的基
4、礎(chǔ)就是一個(gè)線性數(shù)組,這個(gè)數(shù)組就是Entry,Map里面的內(nèi)容都保存在Entry里面。Transient Entrytable;二、HashMap的存取實(shí)現(xiàn):/ 存儲時(shí):int hash = key.hashCode(); / 這個(gè)hashCode方法這里不詳述,只要理解每個(gè)key的hash是一個(gè)固定的int值int index = hash % Entry.length;Entryindex = value;/ 取值時(shí):int hash = key.hashCode();int index = hash % Entry.length;return Entryindex;(1)Put疑問:如果兩
5、個(gè)key通過hash%Entry.length得到的index相同,會不會有覆蓋的危險(xiǎn)?這里HashMap里面用到鏈?zhǔn)綌?shù)據(jù)結(jié)構(gòu)的一個(gè)概念。上面我們提到過Entry類里面有一個(gè)next屬性,作用是指向下一個(gè)Entry。打個(gè)比方, 第一個(gè)鍵值對A進(jìn)來,通過計(jì)算其key的hash得到的index=0,記做:Entry0 = A。一會后又進(jìn)來一個(gè)鍵值對B,通過計(jì)算其index也等于0,現(xiàn)在怎么辦?HashMap會這樣做:B.next = A,Entry0 = B,如果又進(jìn)來C,index也等于0,那么C.next = B,Entry0 = C;這樣我們發(fā)現(xiàn)index=0的地方其實(shí)存取了A,B,C三個(gè)鍵
6、值對,他們通過next這個(gè)屬性鏈接在一起。所以疑問不用擔(dān)心。也就是說數(shù)組中存儲的是最后插入的元素。到這里為止,HashMap的大致實(shí)現(xiàn),我們應(yīng)該已經(jīng)清楚了。public V put(K key, V value) if (key = null) return putForNullKey(value); /null總是放在數(shù)組的第一個(gè)鏈表中 int hash = hash(key.hashCode(); int i = indexFor(hash, table.length); /遍歷鏈表 for (Entry e = tablei; e != null; e = e.next) Object
7、k; /如果key在鏈表中已存在,則替換為新value if (e.hash = hash & (k = e.key) = key | key.equals(k) V oldValue = e.value; e.value = value; e.recordAccess(this); return oldValue; modCount+; addEntry(hash, key, value, i); return null; void addEntry(int hash, K key, V value, int bucketIndex) Entry e = tablebucketIndex;
8、tablebucketIndex = new Entry(hash, key, value, e); /參數(shù)e, 是Entry.next /如果size超過threshold,則擴(kuò)充table大小。再散列 if (size+ = threshold) resize(2 * table.length);當(dāng)然HashMap里面也包含一些優(yōu)化方面的實(shí)現(xiàn),這里也說一下。比如:Entry的長度一定后,隨著map里面數(shù)據(jù)的越來越長,這樣同一個(gè)index的鏈就會很長,會不會影響性能?HashMap里面設(shè)置一個(gè)因子,隨著map的size越來越大,Entry會以一定的規(guī)則加長長度。(2)Getpublic V
9、get(Object key) if (key = null) return getForNullKey(); int hash = hash(key.hashCode(); /先定位到數(shù)組元素,再遍歷該元素處的鏈表 for (Entry e = tableindexFor(hash, table.length); e != null; e = e.next) Object k; if (e.hash = hash & (k = e.key) = key | key.equals(k) return e.value; return null;(3)null key 的存取null key總是存
10、放在Entry數(shù)組的第一個(gè)元素。private V putForNullKey(V value) for (Entry e = table0; e != null; e = e.next) if (e.key = null) V oldValue = e.value; e.value = value; e.recordAccess(this); return oldValue; modCount+; addEntry(0, null, value, 0); return null; private V getForNullKey() for (Entry e = table0; e != nu
11、ll; e = e.next) if (e.key = null) return e.value; return null;(4)確定數(shù)組index:hashCode&table.length(類似取模運(yùn)算)HashMap存取時(shí),都需要計(jì)算當(dāng)前key應(yīng)該對應(yīng)Entry數(shù)組哪個(gè)元素,即計(jì)算數(shù)組下標(biāo);算法如下:/* * Returns index for hash code h. */ static int indexFor(int h, int length) return h & (length-1); 按位取并,作用上相當(dāng)于取模mod或者取余%。這意味著數(shù)組下標(biāo)相同,并不表示hashCode
12、相同。(5)table初始大小 public HashMap(int initialCapacity, float loadFactor) . / Find a power of 2 = initialCapacity int capacity = 1; while (capacity initialCapacity) capacity = initialCapacity的2的n次冪!三、解決Hash沖突的辦法如果兩個(gè)不同對象的hashCode相同,這種現(xiàn)象稱為沖突。開放定址法(線性探測再散列,二次探測再散列,偽隨機(jī)探測再散列)再哈希法鏈地址法建立一個(gè)公共溢出區(qū)Java中hashmap的解決辦
13、法就是采用的鏈地址法。四、再散列rehash過程當(dāng)哈希表的容量超過默認(rèn)容量時(shí),必須調(diào)整table的大小。當(dāng)容量已經(jīng)達(dá)到最大可能值時(shí),那么該方法就將容量調(diào)整到Integer.MAX_VALUE返回,這時(shí),需要創(chuàng)建一張新表,將原表的映射到新表中。void resize(int newCapacity) Entry oldTable = table; int oldCapacity = oldTable.length; if (oldCapacity = MAXIMUM_CAPACITY) threshold = Integer.MAX_VALUE; return; Entry newTable =
14、 new EntrynewCapacity; transfer(newTable); table = newTable; threshold = (int)(newCapacity * loadFactor); /* * Transfers all entries from current table to newTable. */ void transfer(Entry newTable) Entry src = table; int newCapacity = newTable.length; for (int j = 0; j src.length; j+) Entry e = srcj
15、; if (e != null) srcj = null; do Entry next = e.next; /重新計(jì)算index int i = indexFor(e.hash, newCapacity); e.next = newTablei; newTablei = e; e = next; while (e != null); HashTable和HashMap區(qū)別第一,繼承不同。public class Hashtable extends Dictionary implements Mappublic class HashMap extends AbstractMap implemen
16、ts Map第二Hashtable中的方法是同步的,而HashMap中的方法在缺省情況下是非同步的。即是說,在多線程應(yīng)用程序中,不用專門的操作就安全地可以使用Hashtable了;而對于HashMap,則需要額外的同步機(jī)制。但HashMap的同步問題可通過Collections的一個(gè)靜態(tài)方法得到解決:Map Collections.synchronizedMap(Map M)這個(gè)方法返回一個(gè)同步的Map,這個(gè)Map封裝了底層的HashMap的所有方法,使得底層的HashMap即使是在多線程的環(huán)境中也是安全的。第三Hashtable中,key和value都不允許出現(xiàn)null值。在HashMap中
17、,null可以作為鍵,這樣的鍵只有一個(gè);可以有一個(gè)或多個(gè)鍵所對應(yīng)的值為null。當(dāng)get()方法返回null值時(shí),即可以表示 HashMap中沒有該鍵,也可以表示該鍵所對應(yīng)的值為null。因此,在HashMap中不能由get()方法來判斷HashMap中是否存在某個(gè)鍵, 而應(yīng)該用containsKey()方法來判斷。第四,兩個(gè)遍歷方式的內(nèi)部實(shí)現(xiàn)上不同。Hashtable、HashMap都使用了 Iterator。而由于歷史原因,Hashtable還使用了Enumeration的方式 。第五哈希值的使用不同,HashTable直接使用對象的hashCode。而HashMap重新計(jì)算hash值。第
18、六Hashtable和HashMap它們兩個(gè)內(nèi)部實(shí)現(xiàn)方式的數(shù)組的初始大小和擴(kuò)容的方式。HashTable中hash數(shù)組默認(rèn)大小是11,增加的方式是old*2+1。HashMap中hash數(shù)組的默認(rèn)大小是16,而且一定是2的指數(shù)。Hashtable 與 ConcurrentHashMap 的區(qū)別ConcurrentHashMap融合了hashtable和hashmap二者的優(yōu)勢。hashtable是做了同步的,hashmap未考慮同步。所以hashmap在單線程情況下效率較高。hashtable在的多線程情況下,同步操作能保證程序執(zhí)行的正確性。但是hashtable每次同步執(zhí)行的時(shí)候都要鎖住整個(gè)結(jié)構(gòu)。ConcurrentHashMap正是為了解決這個(gè)問題而誕生的。ConcurrentHashMap鎖的方式是稍微細(xì)粒度的。ConcurrentHashMap將hash表分為16個(gè)桶(默認(rèn)值),諸如get,put,remove等常用操作只鎖當(dāng)前需要用到的桶。試想,原來 只能一個(gè)線程進(jìn)入,現(xiàn)在卻能同時(shí)16個(gè)寫線程進(jìn)入(寫線程才需要鎖定,而讀線程幾乎不受限制,之后會提到),并發(fā)性的提升是顯而易見的。更令人驚訝的是ConcurrentHashMap的讀取并發(fā),因?yàn)樵谧x取的大多數(shù)時(shí)候都沒有用到鎖定,所以讀取操作幾乎是完全的并發(fā)操作,而寫操作鎖定的粒度又非常細(xì),比起之前
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 2025-2030跨阻放大器行業(yè)市場現(xiàn)狀供需分析及重點(diǎn)企業(yè)投資評估規(guī)劃分析研究報(bào)告
- 2025-2030花園粉碎機(jī)行業(yè)市場現(xiàn)狀供需分析及重點(diǎn)企業(yè)投資評估規(guī)劃分析研究報(bào)告
- 2025-2030自動開門系統(tǒng)行業(yè)市場現(xiàn)狀供需分析及重點(diǎn)企業(yè)投資評估規(guī)劃分析研究報(bào)告
- 2025-2030粗鋼行業(yè)行業(yè)風(fēng)險(xiǎn)投資發(fā)展分析及投資融資策略研究報(bào)告
- 2025-2030福建省生活垃圾清運(yùn)和處理行業(yè)市場現(xiàn)狀供需分析及重點(diǎn)企業(yè)投資評估規(guī)劃分析研究報(bào)告
- 2025-2030皮卡行業(yè)市場深度調(diào)研及發(fā)展趨勢與投資戰(zhàn)略研究報(bào)告
- 家居配飾安裝合同
- 2025-2030汽車保險(xiǎn)產(chǎn)業(yè)政府戰(zhàn)略管理與區(qū)域發(fā)展戰(zhàn)略研究報(bào)告
- 2025-2030智能語音行業(yè)市場深度調(diào)研及前景趨勢與投資研究報(bào)告
- 2025-2030拼圖玩具行業(yè)市場發(fā)展分析及投資前景研究報(bào)告
- 大學(xué)體育與健康智慧樹知到期末考試答案章節(jié)答案2024年齊魯師范學(xué)院
- 2006用工合同范本
- 小區(qū)消防移交物業(yè)協(xié)議書
- 2024年正式離婚協(xié)議電子版(三篇)
- 中餐餐中服務(wù)服務(wù)流程培訓(xùn)
- 2024春期國開電大本科《現(xiàn)代漢語專題》在線形考(任務(wù)1至6)試題及答案
- 九三學(xué)社申請入社人員簡歷表
- 科普皮膚護(hù)膚知識講座
- 海南東方瑞幫康復(fù)醫(yī)院項(xiàng)目 環(huán)評報(bào)告
- 富貴包治療方法
- 跨國公司經(jīng)營與管理跨國公司的市場營銷管理
評論
0/150
提交評論