java使用HashMap容器添加元素的過(guò)程分析
//逐步分析HashMap類中.put()添加結(jié)點(diǎn)的過(guò)程
? ?public V put(K key, V value) {
? ? ? ?return putVal(hash(key), key, value, false, true);
? ?}
? ?//將key和value傳參進(jìn)put方法中 ? onlyIfAbsent=false evict=true ? 對(duì)key進(jìn)行.hash()方法計(jì)算 .hash()方法如下
? ?static final int hash(Object key) {
? ? ? ?int h;
? ? ? ?return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
? ?}
? ?//返回類型int占用4字節(jié)共32位 key.hashCode()計(jì)算哈希值返回int類型即32位二進(jìn)制數(shù) 哈希值賦值給h ^異或位運(yùn)算 0^0=0 1^0=1 1^1=0相同為0相異為1
? ?//h >>> 16 三個(gè)>為無(wú)符號(hào)右移,將所有位包含符號(hào)位全部右移 ?>>右位移不移動(dòng)符號(hào)位,正數(shù)符號(hào)位補(bǔ)0負(fù)數(shù)符號(hào)位補(bǔ)1
? ?//h為int 32位 ?>>>16即取前16位右移至后16位的位置,前16位補(bǔ)0 ?將結(jié)果和h做^運(yùn)算 返回處理后的hash值 ? ? 這一步的目的是使元素在哈希表中的分布更分散
? ?//putVal(hash(key), key, value, false, true)方法如下
? ?final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
? ? ? ? ? ? ? ? ? boolean evict) {
? ? ? ? ? ? ? ? ? //hash即hash(key)處理后的hash值
? ? ? ? ? ? ? ? ? //onlyIfAbsent – if true, don't change existing value
? ? ? ? ? ? ? ? ? //evict – if false, the table is in creation mode.
? ? ? ?Node<K,V>[] tab; Node<K,V> p; int n, i;
? ? ? ?//定義了結(jié)點(diǎn)數(shù)組tab對(duì)應(yīng)哈希表table ?結(jié)點(diǎn)p
? ? ? ?if ((tab = table) == null || (n = tab.length) == 0) ? ? ? ?//在判斷==前括號(hào)內(nèi)將哈希表賦值給tab 第一次put結(jié)點(diǎn)時(shí)哈希表為空 往下執(zhí)行初始化
? ? ? ? ? ?n = (tab = resize()).length; ? ? ? ? ? ?//.resize()方法用于數(shù)組的初始化及擴(kuò)容 初始化后tab為長(zhǎng)度16的數(shù)組 ? ?短路或||當(dāng)tab==null為false時(shí)會(huì)執(zhí)行n=tab.length 如果前面true則不執(zhí)行該賦值 ?進(jìn)而在語(yǔ)句塊內(nèi)賦值16 ?所以再往下時(shí)無(wú)論哪種情況n都代表哈希表的長(zhǎng)度 ?.resize()方法之后分析
? ? ? ?if ((p = tab[i = (n - 1) & hash]) == null) ? ? ? ? ?//哈希表的長(zhǎng)度固定為2的n次冪,用二進(jìn)制表示均為10000后面n個(gè)0的格式 ? ? n-1會(huì)使原來(lái)1的后面所有0變?yōu)? 15為1111 31為11111 ? ? ?從0到1111即15總共為16個(gè)數(shù)對(duì)應(yīng)index0到15 ? ?用1111和處理后的hash值做&與運(yùn)算和hash%16是同樣的效果,因?yàn)?6為10000,所有高于五位的部分都是16的2^n倍,實(shí)際的余數(shù)就是最后四位的值 ? ? ?這也是強(qiáng)制規(guī)定哈希表長(zhǎng)度必須為2的n次冪的目的,用1111n個(gè)1&hash代替hash%capacity計(jì)算以提高計(jì)算效率 ? ? &與運(yùn)算的最小值為0最大值為長(zhǎng)度-1和index對(duì)應(yīng) ? ? ?將index賦值給i,將tab[i]賦值給p,判斷p是否為空,為空則直接添加結(jié)點(diǎn),不為空需要進(jìn)行比較是否重復(fù)
? ? ? ? ? ?tab[i] = newNode(hash, key, value, null); ? ? ? //當(dāng)p即tab[i]為空?qǐng)?zhí)行語(yǔ)句,newNode()方法會(huì)生成新的結(jié)點(diǎn)存儲(chǔ)KV ? ?這里存儲(chǔ)的是處理后的hash值,并不是%length的余數(shù),存儲(chǔ)hash值用于哈希表擴(kuò)容或同index元素的hash比較或鏈表與紅黑樹(shù)轉(zhuǎn)換等 ? ? ?最后一個(gè)參數(shù)next=null,put結(jié)點(diǎn)會(huì)放在表尾,所以將next設(shè)為null
? ? ? ?else { ? ? ?//p不為空的情況
? ? ? ? ? ?Node<K,V> e; K k; ? ? ? //定義結(jié)點(diǎn)e key的k
? ? ? ? ? ?if (p.hash == hash &&
? ? ? ? ? ? ? ?((k = p.key) == key || (key != null && key.equals(k)))) ? ? ?//如果p的hash和新put的hash相等&&短路與(如果false就不對(duì)k賦值) ? ? 將p.key賦值給k,判斷兩個(gè)key是否相同||短路或 ? ? ?新put的key不為空&&短路與兩個(gè)key調(diào)用equals()方法判斷是否相同 ? ? 所以先判斷hash,為true才會(huì)調(diào)用equals()方法,如果自定義對(duì)象要使用HashMap/HashSet的話不僅要重寫.equals()還要重寫.hashCode()
? ? ? ? ? ? ? ?e = p; ? ? ? ?//當(dāng)判斷兩個(gè)key相同后會(huì)將p賦值給e
? ? ? ? ? ?else if (p instanceof TreeNode) ? ? ? ? //如果兩個(gè)key不同,再判斷當(dāng)前索引位是否為紅黑樹(shù)結(jié)構(gòu),如果為紅黑樹(shù)則執(zhí)行紅黑樹(shù)添加樹(shù)結(jié)點(diǎn)的方法
? ? ? ? ? ? ? ?e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value); ? ? //引用變量p為Node<K,V>類型,強(qiáng)轉(zhuǎn)為樹(shù)結(jié)點(diǎn) ? ? ?如果為紅黑樹(shù)結(jié)構(gòu),這里的p即tab[i]不再是表頭結(jié)點(diǎn),是樹(shù)的根節(jié)點(diǎn)root
? ? ? ? ? ?else { ? ? ? ?//如果兩個(gè)key不同,并且當(dāng)前結(jié)構(gòu)為單向鏈表
? ? ? ? ? ? ? ?for (int binCount = 0; ; ++binCount) {
? ? ? ? ? ? ? ? ? ?if ((e = p.next) == null) { ? ? ? ? ? ? //binCount計(jì)數(shù)器,將e設(shè)為p的直接后繼結(jié)點(diǎn),當(dāng)直接后繼結(jié)點(diǎn)為null即遍歷到達(dá)表尾時(shí),鏈表中所有的結(jié)點(diǎn)都和新put的key不同,則將新結(jié)點(diǎn)添加至表尾
? ? ? ? ? ? ? ? ? ? ? ?p.next = newNode(hash, key, value, null); ? ? ? ? ? //將原表尾結(jié)點(diǎn)的next指向新結(jié)點(diǎn),完成表尾的變更 ? ? ?雖然這里將p.next從null變?yōu)樾陆Y(jié)點(diǎn),但e仍然指向null,當(dāng)p.next賦值給e時(shí)e指向的是null而不是表尾.next,表尾變更了但e沒(méi)有變
? ? ? ? ? ? ? ? ? ? ? ?if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st ? ? ? ? ? ?//從表頭至表尾為size,當(dāng)只有表頭結(jié)點(diǎn)時(shí)binCount為0,size為1,即binCount為size-1 ? ?當(dāng)size-1大于等于轉(zhuǎn)換為紅黑樹(shù)的閾8-1時(shí)
? ? ? ? ? ? ? ? ? ? ? ? ? ?treeifyBin(tab, hash); ? ? ? ? ?//treeifyBin()方法先判斷哈希表長(zhǎng)度是否達(dá)到MIN_TREEIFY_CAPACITY=64,false則進(jìn)行擴(kuò)容resize,true則將鏈表轉(zhuǎn)換為紅黑樹(shù),轉(zhuǎn)換操作是哈希表中每個(gè)哈希桶單獨(dú)進(jìn)行的,別的哈希桶如果size沒(méi)有達(dá)到8仍然是單向鏈表
? ? ? ? ? ? ? ? ? ? ? ?break;
? ? ? ? ? ? ? ? ? ?}
? ? ? ? ? ? ? ? ? ?if (e.hash == hash &&
? ? ? ? ? ? ? ? ? ? ? ?((k = e.key) == key || (key != null && key.equals(k)))) ? ? ? ? //比較鏈表中的每一個(gè)結(jié)點(diǎn),如果某一個(gè)結(jié)點(diǎn)和新put的key相同則break,這時(shí)e指向的是和key相同的這個(gè)結(jié)點(diǎn)
? ? ? ? ? ? ? ? ? ? ? ?break;
? ? ? ? ? ? ? ? ? ?p = e; ? ? ? ? ?//迭代,結(jié)點(diǎn)e比較完賦值給p,下一輪e變?yōu)楹罄^結(jié)點(diǎn)繼續(xù)判斷
? ? ? ? ? ? ? ?}
? ? ? ? ? ?} ? ? ? ? ? //從上邊表頭結(jié)點(diǎn)的if判斷到elseif到else,e分為兩種情況,一種是key重復(fù)時(shí)e指向和key相同的原結(jié)點(diǎn),一種是key不重復(fù)所以新增了結(jié)點(diǎn)時(shí)e為null
? ? ? ? ? ?if (e != null) { // existing mapping for key
? ? ? ? ? ? ? ?V oldValue = e.value; ? ? ? //將結(jié)點(diǎn)原來(lái)的value元素緩存,之后返回
? ? ? ? ? ? ? ?if (!onlyIfAbsent || oldValue == null)
? ? ? ? ? ? ? ? ? ?e.value = value; ? ? ? ?//這里用到了之前設(shè)定的onlyIfAbsent=false,非運(yùn)算后為true,執(zhí)行重復(fù)key的value覆蓋,不增加新的結(jié)點(diǎn),修改原key對(duì)應(yīng)的value元素,返回原來(lái)的value
? ? ? ? ? ? ? ?afterNodeAccess(e);
? ? ? ? ? ? ? ?return oldValue; ? ? ? ?//如果是發(fā)生value的替換會(huì)在這里返回原value結(jié)束方法,如果是新增結(jié)點(diǎn)會(huì)跳過(guò)這個(gè)if語(yǔ)句執(zhí)行后面的操作
? ? ? ? ? ?}
? ? ? ?}
? ? ? ?++modCount; ? ? ? ? //修改操作的計(jì)數(shù)器
? ? ? ?if (++size > threshold) ? ? ? ? //前面的操作如果是key重復(fù)進(jìn)行覆蓋,到這里之前已經(jīng)return結(jié)束方法了,只有增加新結(jié)點(diǎn)時(shí)才會(huì)繼續(xù)執(zhí)行,這里的size指結(jié)點(diǎn)的總數(shù),因?yàn)樾略隽艘粋€(gè)結(jié)點(diǎn)所以++size,threshold是通過(guò)前面調(diào)用的resize()方法賦值的屬性,是load factor負(fù)載因子0.75f*數(shù)組長(zhǎng)度capacity的值,if條件的意思為當(dāng)結(jié)點(diǎn)總數(shù)大于閾值時(shí)進(jìn)行resize擴(kuò)容
? ? ? ? ? ?resize();
? ? ? ?afterNodeInsertion(evict);
? ? ? ?return null; ? ? ? ? ? ?//沒(méi)有發(fā)生value覆蓋會(huì)返回null
? ?}
//進(jìn)一步分析.resize()方法的擴(kuò)容過(guò)程
? ?final Node<K,V>[] resize() { ? ? ? ? ? ?//返回結(jié)點(diǎn)數(shù)組,即擴(kuò)容后的哈希表
? ? ? ?Node<K,V>[] oldTab = table; ? ? ? ? ? ? //將原哈希表賦值給oldTab
? ? ? ?int oldCap = (oldTab == null) ? 0 : oldTab.length; ? ? ? ? ?//原哈希表容量,初次put結(jié)點(diǎn)時(shí)數(shù)組為null
? ? ? ?int oldThr = threshold; ? ? ? ? ? ? //將原哈希表的負(fù)載因子的閾值賦值給oldThr
? ? ? ?int newCap, newThr = 0; ? ? ? ? ? ? //初始化新的容量和閾值
? ? ? ?if (oldCap > 0) { ? ? ? ? ? ? ? //當(dāng)原容量大于0,即集合已經(jīng)添加過(guò)結(jié)點(diǎn)時(shí)
? ? ? ? ? ?if (oldCap >= MAXIMUM_CAPACITY) {
? ? ? ? ? ? ? ?threshold = Integer.MAX_VALUE;
? ? ? ? ? ? ? ?return oldTab; ? ? ? ? ?//MAXIMUM_CAPACITY=1<<30,哈希表的最大容量,如果原容量已經(jīng)達(dá)到最大,則不再擴(kuò)容,將閾值調(diào)整為int最大值(1<<31)-1,這樣size永遠(yuǎn)不會(huì)大于閾值,不會(huì)再觸發(fā)擴(kuò)容,將原哈希表返回,沒(méi)有對(duì)哈希表進(jìn)行變更
? ? ? ? ? ?}
? ? ? ? ? ?else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY &&
? ? ? ? ? ? ? ? ? ? oldCap >= DEFAULT_INITIAL_CAPACITY) ? ? ? ? ? ?//這里對(duì)新容量進(jìn)行賦值,左移1即*2,通過(guò)左移保證容量永遠(yuǎn)是2的n次冪(二進(jìn)制為10000后面n個(gè)0),而最大容量之所以是1<<30是因?yàn)樵偻笠频脑?會(huì)被移至首位即符號(hào)位,int32位,1000后面31個(gè)0為-2^31,1<<30為01000后面30個(gè)0
? ? ? ? ? ? ? ?newThr = oldThr << 1; // double threshold ? ? ? ? ? //elseif判斷為當(dāng)新容量小于最大容量&&短路與 ?原容量大于等于默認(rèn)初始容量16時(shí),將原閾值<<1左移1賦值給新閾值,閾值是負(fù)載因子0.75f*容量,0.75即3/4,容量為2^n,所以乘法結(jié)果一定為整數(shù),每一次擴(kuò)容都是左移1即*2,閾值的增加也使用左移1代替oldThr*2或者0.75*newCap使計(jì)算效率提高
? ? ? ?}
? ? ? ?else if (oldThr > 0) // initial capacity was placed in threshold
? ? ? ? ? ?newCap = oldThr; ? ? ? ? ? ?//當(dāng)原容量等于0而原閾值大于0時(shí),將新容量變?yōu)殚撝?/span>
? ? ? ?else { ? ? ? ? ? ? ? // 當(dāng)原容量和原閾值都為0,即初次添加結(jié)點(diǎn)時(shí)調(diào)用的擴(kuò)容
? ? ? ? ? ?newCap = DEFAULT_INITIAL_CAPACITY; ? ? ? ? ?//將容量變?yōu)槟J(rèn)初始容量16
? ? ? ? ? ?newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY); ? ? ? ? //將閾值變?yōu)?.75f*16即12,雖然結(jié)果一定是整數(shù),但數(shù)據(jù)類型為float,需要強(qiáng)轉(zhuǎn)int,只有初次擴(kuò)容會(huì)進(jìn)行乘法運(yùn)算,之后的閾值都隨容量做左移運(yùn)算
? ? ? ?}
? ? ? ?if (newThr == 0) { ? ? ? ? ?//這里對(duì)新閾值進(jìn)行判斷,上面的語(yǔ)句中只有一種情況沒(méi)有對(duì)newThr賦新的值,即else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY && oldCap >= DEFAULT_INITIAL_CAPACITY)為false,這意味著原容量在[1,15]或[(1<<29)+1,(1<<30)-1]區(qū)間內(nèi),這時(shí)容量不是2^n,不屬于正常情況這里不再分析
? ? ? ? ? ?float ft = (float)newCap * loadFactor;
? ? ? ? ? ?newThr = (newCap < MAXIMUM_CAPACITY && ft < (float)MAXIMUM_CAPACITY ?
? ? ? ? ? ? ? ? ? ? ?(int)ft : Integer.MAX_VALUE);
? ? ? ?}
? ? ? ?threshold = newThr; ? ? ? ? //將新閾值賦值給閾值屬性,用作以后的size和threshold比較
? ? ? ?@SuppressWarnings({"rawtypes","unchecked"})
? ? ? ?Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap]; ? ? ? ? //創(chuàng)建新的結(jié)點(diǎn)數(shù)組,泛型類數(shù)組需要強(qiáng)轉(zhuǎn)
? ? ? ?table = newTab; ? ? ? ? //將哈希表數(shù)組變?yōu)樾聰?shù)組
? ? ? ?if (oldTab != null) { ? ? ? ? ? //判斷原數(shù)組是否不為空,當(dāng)初次put結(jié)點(diǎn)時(shí)不執(zhí)行
? ? ? ? ? ?for (int j = 0; j < oldCap; ++j) { ? ? ? ? ?//遍歷原哈希表
? ? ? ? ? ? ? ?Node<K,V> e;
? ? ? ? ? ? ? ?if ((e = oldTab[j]) != null) { ? ? ? ? ?//將表頭結(jié)點(diǎn)/根節(jié)點(diǎn)取出
? ? ? ? ? ? ? ? ? ?oldTab[j] = null; ? ? ? ? ? //將該位置賦null
? ? ? ? ? ? ? ? ? ?if (e.next == null) ? ? ? ? ? ? //如果只有表頭結(jié)點(diǎn)
? ? ? ? ? ? ? ? ? ? ? ?newTab[e.hash & (newCap - 1)] = e; ? ? ? ? ?//用結(jié)點(diǎn)的處理后的hash值和新容量-1即n個(gè)111進(jìn)行與運(yùn)算即%newCap,計(jì)算出結(jié)點(diǎn)在新哈希表中的索引,將結(jié)點(diǎn)放入,每次擴(kuò)容都要對(duì)集合內(nèi)所有結(jié)點(diǎn)重新計(jì)算位置,在單向鏈表內(nèi)只有表頭的情況下不需要擔(dān)心新哈希表的對(duì)應(yīng)位置會(huì)不會(huì)在遍歷過(guò)程中已存有結(jié)點(diǎn)造成覆蓋,擴(kuò)容是左移1,索引位的范圍也跟著向左擴(kuò)展1位二進(jìn)制數(shù),新的索引位只有兩種數(shù)的可能,一種是新增的最高位為0,新的索引=原索引,另一種是為1,所有可能與表頭結(jié)點(diǎn)索引位沖突的結(jié)點(diǎn)都一定在原表中與表頭結(jié)點(diǎn)沖突,即被鏈至表頭結(jié)點(diǎn)next,但因?yàn)楸眍^next=null,所以一定沒(méi)有別的結(jié)點(diǎn)和表頭結(jié)點(diǎn)沖突,新索引位一定為null
? ? ? ? ? ? ? ? ? ?else if (e instanceof TreeNode) ? ? ? ? ? ? //判斷當(dāng)前哈希桶是否為紅黑樹(shù)結(jié)構(gòu),紅黑樹(shù)結(jié)構(gòu)當(dāng)結(jié)點(diǎn)數(shù)降至6會(huì)轉(zhuǎn)回單向鏈表,所以上面只有表頭結(jié)點(diǎn)的情況一定是單向鏈表結(jié)構(gòu)
? ? ? ? ? ? ? ? ? ? ? ?((TreeNode<K,V>)e).split(this, newTab, j, oldCap); ? ? ? ? ?//引用變量e編譯類型為Node類,需要強(qiáng)轉(zhuǎn)樹(shù)結(jié)點(diǎn),對(duì)所有樹(shù)結(jié)點(diǎn)進(jìn)行索引的轉(zhuǎn)換操作
? ? ? ? ? ? ? ? ? ?else { // preserve order保持秩序 ? ? ? ? ? ?//當(dāng)單向鏈表內(nèi)有多個(gè)結(jié)點(diǎn)的情況
? ? ? ? ? ? ? ? ? ? ? ?Node<K,V> loHead = null, loTail = null; ? ? ? ? //head頭即表頭結(jié)點(diǎn),tail尾即表尾結(jié)點(diǎn)
? ? ? ? ? ? ? ? ? ? ? ?Node<K,V> hiHead = null, hiTail = null; ? ? ? ? //lo即low,hi即high
? ? ? ? ? ? ? ? ? ? ? ?Node<K,V> next;
? ? ? ? ? ? ? ? ? ? ? ?do {
? ? ? ? ? ? ? ? ? ? ? ? ? ?next = e.next;
? ? ? ? ? ? ? ? ? ? ? ? ? ?if ((e.hash & oldCap) == 0) { ? ? ? ? ? //原容量為1000后面n個(gè)0,所以&與運(yùn)算的目的就是看索引位范圍向左擴(kuò)展的那一位是不是0,因?yàn)樾碌乃饕皇苣且晃挥绊懼挥袃煞N可能,一種是和原索引位相同即low位對(duì)應(yīng)當(dāng)前for循環(huán)的j,一種是比原索引位高oldCap位即high位 ? ? 與運(yùn)算結(jié)果為0時(shí),結(jié)點(diǎn)e會(huì)放到low位
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?if (loTail == null) ? ? ? ? ? ? ? ? //e放low位時(shí)判斷l(xiāng)ow位的表尾結(jié)點(diǎn)loTail是否null
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?loHead = e; ? ? ? ? ? ? //如果low位為空將e設(shè)為表頭結(jié)點(diǎn)
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?else
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?loTail.next = e; ? ? ? ? ? ?//如果表尾存在結(jié)點(diǎn)則將e鏈至表尾
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?loTail = e; ? ? ? ? ? ? //初次添加表頭后表尾也指向表頭結(jié)點(diǎn),之后每次新增結(jié)點(diǎn)都會(huì)指向新的表尾結(jié)點(diǎn)
? ? ? ? ? ? ? ? ? ? ? ? ? ?}
? ? ? ? ? ? ? ? ? ? ? ? ? ?else { ? ? ? ? ? ? ?//e放high位的情況
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?if (hiTail == null) ? ? ? ? //原理同上,如果表尾為null則存表頭,如果表尾有結(jié)點(diǎn)則鏈至表尾
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?hiHead = e;
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?else
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?hiTail.next = e;
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?hiTail = e;
? ? ? ? ? ? ? ? ? ? ? ? ? ?}
? ? ? ? ? ? ? ? ? ? ? ?} while ((e = next) != null); ? ? ? ? ? //單向鏈表中只有表尾結(jié)點(diǎn).next為null,當(dāng)e變?yōu)閚ull即鏈表遍歷結(jié)束
? ? ? ? ? ? ? ? ? ? ? ?if (loTail != null) {
? ? ? ? ? ? ? ? ? ? ? ? ? ?loTail.next = null; ? ? ? ? ? ? //當(dāng)low位有結(jié)點(diǎn)時(shí)將表尾結(jié)點(diǎn).next賦null,因?yàn)樵瓎蜗蜴湵碇性摻Y(jié)點(diǎn)可能有后繼結(jié)點(diǎn)(后繼結(jié)點(diǎn)放到high位的情況)
? ? ? ? ? ? ? ? ? ? ? ? ? ?newTab[j] = loHead; ? ? ? ? ? ? //將表頭賦值給新表的原索引位
? ? ? ? ? ? ? ? ? ? ? ?}
? ? ? ? ? ? ? ? ? ? ? ?if (hiTail != null) {
? ? ? ? ? ? ? ? ? ? ? ? ? ?hiTail.next = null; ? ? ? ? ? ? //原理同上,將high位表尾結(jié)點(diǎn).next賦null
? ? ? ? ? ? ? ? ? ? ? ? ? ?newTab[j + oldCap] = hiHead; ? ? ? ? ? ?//以oldCap=16為例,oldCap二進(jìn)制為10000,原結(jié)點(diǎn)的索引從0000到1111即0-15位,e.hash & oldCap即判斷10000的1的那一位,如果結(jié)果為1,新的索引位為1xxxx即原索引位+10000(十進(jìn)制為16即原容量oldCap),即新的索引位為原索引位+oldCap,所以low位為j,high位為j+oldCap
? ? ? ? ? ? ? ? ? ? ? ?}
? ? ? ? ? ? ? ? ? ?}
? ? ? ? ? ? ? ?}
? ? ? ? ? ?}
? ? ? ?}
? ? ? ?return newTab; ? ? ? ? ?//擴(kuò)容和秩序維護(hù)完成,返回新哈希表
? ?}