久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

Java 集合框架 HashSet 和HashMap 源碼剖析

 江海報(bào)覽 2016-05-27

總體介紹

之所以把HashSet和HashMap放在一起講解,,是因?yàn)槎咴贘ava里有著相同的實(shí)現(xiàn),,前者僅僅是對(duì)后者做了一層包裝,,也就是說HashSet里面有一個(gè)HashMap(適配器模式),。因此本文將重點(diǎn)分析HashMap,。

HashMap實(shí)現(xiàn)了Map接口,,允許放入null元素,,除該類未實(shí)現(xiàn)同步外,,其余跟Hashtable大致相同,,跟TreeMap不同,該容器不保證元素順序,,根據(jù)需要該容器可能會(huì)對(duì)元素重新哈希,,元素的順序也會(huì)被重新打散,因此不同時(shí)間迭代同一個(gè)HashMap的順序可能會(huì)不同,。

根據(jù)對(duì)沖突的處理方式不同,,哈希表有兩種實(shí)現(xiàn)方式,一種開放地址方式(Open addressing),,另一種是沖突鏈表方式(Separate chaining with linked lists),。Java HashMap采用的是沖突鏈表方式

從上圖容易看出,,如果選擇合適的哈希函數(shù),,put()get()方法可以在常數(shù)時(shí)間內(nèi)完成。但在對(duì)HashMap進(jìn)行迭代時(shí),,需要遍歷整個(gè)table以及后面跟的沖突鏈表,。因此對(duì)于迭代比較頻繁的場(chǎng)景,不宜將HashMap的初始大小設(shè)的過大,。

有兩個(gè)參數(shù)可以影響HashMap的性能:初始容量(inital capacity)和負(fù)載系數(shù)(load factor),。初始容量指定了初始table的大小,負(fù)載系數(shù)用來指定自動(dòng)擴(kuò)容的臨界值,。當(dāng)entry的數(shù)量超過capacity*load_factor時(shí),,容器將自動(dòng)擴(kuò)容并重新哈希。對(duì)于插入元素較多的場(chǎng)景,,將初始容量設(shè)大可以減少重新哈希的次數(shù),。

將對(duì)向放入到HashMap或HashSet中時(shí),有兩個(gè)方法需要特別關(guān)心:hashCode()equals()hashCode()方法決定了對(duì)象會(huì)被放到哪個(gè)bucket里,,當(dāng)多個(gè)對(duì)象的哈希值沖突時(shí),,equals()方法決定了這些對(duì)象是否是“同一個(gè)對(duì)象”。所以,,如果要將自定義的對(duì)象放入到HashMapHashSet中,,需要@Override hashCode()equals()方法。

方法剖析

get()

get(Object key)方法根據(jù)指定的key值返回對(duì)應(yīng)的value,,該方法調(diào)用了getEntry(Object key)得到相應(yīng)的entry,,然后返回entry.getValue()。因此getEntry()是算法的核心,。

算法思想是首先通過hash()函數(shù)得到對(duì)應(yīng)bucket的下標(biāo),,然后依次遍歷沖突鏈表,通過key.equals(k)方法來判斷是否是要找的那個(gè)entry,。

上圖中hash(k)&(table.length-1)等價(jià)于hash(k)%table.length,,原因是HashMap要求table.length必須是2的指數(shù),因此table.length-1就是二進(jìn)制低位全是1,,跟hash(k)相與會(huì)將哈希值的高位全抹掉,,剩下的就是余數(shù)了。

//getEntry()方法final Entry getEntry(Object key) { ...... int hash = (key == null) ? 0 : hash(key); for (Entry e = table[hash&(table.length-1)];//得到?jīng)_突鏈表 e != null; e = e.next) {//依次遍歷沖突鏈表中的每個(gè)entry Object k; //依據(jù)equals()方法判斷是否相等 if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) return e; } return null;}

put()

put(K key, V value)方法是將指定的key, value對(duì)添加到map里,。該方法首先會(huì)對(duì)map做一次查找,,看是否包含該元組,如果已經(jīng)包含則直接返回,,查找過程類似于getEntry()方法,;如果沒有找到,則會(huì)通過addEntry(int hash, K key, V value, int bucketIndex)方法插入新的entry,,插入方式為頭插法,。

//addEntry()void addEntry(int hash, K key, V value, int bucketIndex) { if ((size >= threshold) && (null != table[bucketIndex])) { resize(2 * table.length);//自動(dòng)擴(kuò)容,并重新哈希 hash = (null != key) ? hash(key) : 0; bucketIndex = hash & (table.length-1);//hash%table.length } //在沖突鏈表頭部插入新的entry Entry e = table[bucketIndex]; table[bucketIndex] = new Entry<>(hash, key, value, e); size++;}

remove()

remove(Object key)的作用是刪除key值對(duì)應(yīng)的entry,,該方法的具體邏輯是在removeEntryForKey(Object key)里實(shí)現(xiàn)的,。removeEntryForKey()方法會(huì)首先找到key值對(duì)應(yīng)的entry,然后刪除該entry(修改鏈表的相應(yīng)指針),。查找過程跟getEntry()過程類似,。

//removeEntryForKey()final Entry removeEntryForKey(Object key) { ...... int hash = (key == null) ? 0 : hash(key); int i = indexFor(hash, table.length);//hash&(table.length-1) Entry prev = table[i];//得到?jīng)_突鏈表 Entry e = prev; while (e != null) {//遍歷沖突鏈表 Entry next = e.next; Object k; if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) {//找到要?jiǎng)h除的entry modCount++; size--; if (prev == e) table[i] = next;//刪除的是沖突鏈表的第一個(gè)entry else prev.next = next; return e; } prev = e; e = next; } return e;}

HashSet

前面已經(jīng)說過HashSet是對(duì)HashMap的簡(jiǎn)單包裝,對(duì)HashSet的函數(shù)調(diào)用都會(huì)轉(zhuǎn)換成合適的HashMap方法,,因此HashSet的實(shí)現(xiàn)非常簡(jiǎn)單,,只有不到300行代碼。這里不再贅述,。

//HashSet是對(duì)HashMap的簡(jiǎn)單包裝public class HashSet{ ...... private transient HashMap map;//HashSet里面有一個(gè)HashMap // Dummy value to associate with an Object in the backing Map private static final Object PRESENT = new Object(); public HashSet() { map = new HashMap<>(); } ...... public boolean add(E e) {//簡(jiǎn)單的方法轉(zhuǎn)換 return map.put(e, PRESENT)==null; } ......}


    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,,所有內(nèi)容均由用戶發(fā)布,,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式,、誘導(dǎo)購(gòu)買等信息,,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,,請(qǐng)點(diǎn)擊一鍵舉報(bào),。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多