Java HashMap 扩容过程分析
Posted cbhe
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java HashMap 扩容过程分析相关的知识,希望对你有一定的参考价值。
1 final Node<K, V> resize(){ 2 3 // 用于存储重新散列后的数组 4 Node<K, V>[] newTab; 5 6 // 如果原来的数组是空的,则resize执行的是初始化操作,而不是扩容操作 7 if(table == null){ 8 // 初始容量为16 9 int cap = DEFAULT_CAPACITY;// 1<<<4 10 11 // 初始的加载因子为0.75,即容量使用到3/4时就要再次扩容 12 loadFactor = DEFAULT_LOADFACTOR; 13 14 // 设置扩容阈值 15 threshold = (int)(cap * loadFactor); 16 17 newTab = (Node<K, V>[])(new Node[cap]); 18 return newTab; 19 } 20 21 // ... 省略了细节处理,例如容量到达最大值时应该怎么办,本程序段主要讲述扩容流程 22 23 // 如果原来的数组不为空,则先扩容,再把原来的数据重新散列到新的扩容后的数组中 24 int oldCap = table.length; 25 int newCap = oldCap << 1; 26 threshold = newCap * loadFactor; 27 newTab = (Node<K, V>[])(new Node[newCap]); 28 29 // 循环遍历原来的数组,进行重新散列 30 for(int i = 0; i < table.length; i++){ 31 32 if(table[i] == null){ 33 continue; 34 } 35 36 Node<K,V> e = table[i]; 37 table[i] = null; 38 39 // 数组中每个元素下都是一个链表 40 // 如果链表只有一个元素,那么直接将其放到新位置 41 if(e.next == null){ 42 newTab[e.hash & (newCap-1)] = e; 43 continue; 44 } 45 46 // 如果链表中有多个元素,则需要将其分成两个链表 47 // 为什么是两个链表呢?因为当 hash&(oldCap-1) == i 时, 48 // hash&(newCap-1) 只会有两个取值:i 和 i+oldCap 49 // 证明: 50 // 假设 oldCap = 16 = 0b10000 51 // 则 newCap = 16 <<< 1 = 0b100000 52 // 则 oldCap - 1 = 0b1111 53 // newCap - 1 = 0b11111 54 // 则 hash&(oldCap-1) 与 hash&(newCap-1) 只有 从又向左数第五位不同 55 // 又因为 0b10000 = oldCap 56 // 所以 hash&(newCap-1) == hash&(oldCap-1) == i 57 // 或 hash&(newCap-1) == hash&(oldCap-1)+oldCap == i+oldCap 58 59 // 链表1:放在原处,即 hash&(newCap-1) = hash&(oldCap-1) = i 60 Node<K, V> hiHead, hiTail; 61 // 链表2:放在 i+oldCap处,即hash&(newCap-1) = hash&(oldCap-1)+oldCap = i+oldCap 62 Node<K, V> loHead, loTail; 63 do{ 64 // 将原来链表中的元素分类放到链表1、2中 65 66 // 如果散列值与原来一样(i) 67 if((e.hash & (oldCap-1)) == (e.hash & (newCap-1))){ 68 if(loHead == null){ 69 loHead = e; 70 } else { 71 loTail.next = e; 72 } 73 loTail = e; 74 } else { 75 // 如果散列值与原来不一样(i+oldCap) 76 if(hiHead == null){ 77 hiHead = e; 78 } else { 79 hiTail.next = e; 80 } 81 hiTail = e; 82 } 83 e = e.next; 84 } while(e != null); 85 86 if(hiHead != null){ 87 hiTail.next = null; 88 89 // 放在新位置 90 newTab[i+oldCap] = hiHead; 91 } 92 if(loHead != null){ 93 loTail.next = null; 94 95 // 放在原处 96 newTab[i] = loHead; 97 } 98 } 99 100 return newTab; 101 }
以上是关于Java HashMap 扩容过程分析的主要内容,如果未能解决你的问题,请参考以下文章