本篇内容介绍了“HashMap底层源码是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!
final V putVal(int hash, K key, V value, boolean onlyIfAbsent, boolean evict) { // tab:Node数组 // p:Node节点 // n:Node数组的总长度 // i:当前节点的下标 Node<K,V>[] tab; Node<K,V> p; int n, i; // 判断Node数组是否为空,如果为空并且数组长度为0,则对Node数组进行初始化 if ((tab = table) == null || (n = tab.length) == 0) n = (tab = resize()).length; // 对Hash值进行位与运算,赋值给i,得出该key所在的数组下标 // 如果tab[i]是空的,那么新建一个Node并存入数组 if ((p = tab[i = (n - 1) & hash]) == null) tab[i] = newNode(hash, key, value, null); // 以上情况都不是 else { // e: 需要修改的节点 // k: 节点的key值 Node<K,V> e; K k; // 判断Node数组饿的第一个节点的Hash值是不是和Hash一致,并且在Hash一致的情况下, // 两者的Key是否一致,一直的话,将需要修改的节点变为当前节点 if (p.hash == hash && ((k = p.key) == key || (key != null && key.equals(k)))) e = p; // 如果P节点是树节点, 将使用红黑树的形式存储e节点 else if (p instanceof TreeNode) e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value); // 如果是普通节点 else { for (int binCount = 0; ; ++binCount) { // 如果遍历到最后一个节点,新建Node存储数据 // 判断他的长度是否大于链表设定长度 // 如果大于设定长度,则将链表转换为红黑树 if ((e = p.next) == null) { p.next = newNode(hash, key, value, null); if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st treeifyBin(tab, hash); break; } // 遍历的节点如果Hash值一致,key值也一致,则跳出循环 if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) break; p = e; } } // 如果e不为空 如果onlyIfAbsent参数(覆盖更新) // 设置为true或者e的Value是null // 将e的Value修改为传入的Value // * afterNodeAccess为LinkedHashMap函数,在HashMap中没有进行任何操作 if (e != null) { // existing mapping for key V oldValue = e.value; if (!onlyIfAbsent || oldValue == null) e.value = value; afterNodeAccess(e); return oldValue; } } ++modCount; // 如果HashMap的总长度大于设定长度,就进行resize操作 if (++size > threshold) resize(); // * afterNodeInsertion为LinkedHashMap函数,在HashMap中没有进行任何操作 afterNodeInsertion(evict); return null; }
// 对table进行初始化或者两倍扩容 final Node<K,V>[] resize() { // oldTab: 数据 // oldCap: 老容量(原Node数组长度) // oldThr: 老阀值(总数据量大于阀值则扩容) // newCap, newThr: 新容量和新阀值 Node<K,V>[] oldTab = table; int oldCap = (oldTab == null) ? 0 : oldTab.length; int oldThr = threshold; int newCap, newThr = 0; // 如果oldCap大于0 if (oldCap > 0) { // oldCap >= 最大的容量(1073741824) // 将全局的阀值修改为最大的Integer(2147483647) if (oldCap >= MAXIMUM_CAPACITY) { threshold = Integer.MAX_VALUE; return oldTab; } // 解释一下 newCap = oldCap << 1 和 // newCap = oldCap * 2的结果是一样, // 如果newCap < 最大容量 并且 oldCap >= 默认初始化容量(16) // 那么 newThr = oldThr * 2 else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY && oldCap >= DEFAULT_INITIAL_CAPACITY) newThr = oldThr << 1; } // 如果oldThr大于0 else if (oldThr > 0) // newCap = oldThr newCap = oldThr; // 以上情况都不是 else { // zero initial threshold signifies using defaults // newCap = 默认初始化容量 // newThr = 默认负载因子 * 默认初始化容量 newCap = DEFAULT_INITIAL_CAPACITY; newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY); } // 如果newThr 为0 if (newThr == 0) { // ft: 新的负载数量 // ft = newCap * 负载因子 float ft = (float)newCap * loadFactor; // 如果newCap < 最大容量 && ft < 最大容量 // 那么 newThr = (int) ft // 否则 newThr = 最大Integer值 newThr = (newCap < MAXIMUM_CAPACITY && ft < (float)MAXIMUM_CAPACITY ? (int)ft : Integer.MAX_VALUE); } // 全局的阀值修改 threshold = newThr; @SuppressWarnings({"rawtypes","unchecked"}) Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap]; table = newTab; if (oldTab != null) { for (int j = 0; j < oldCap; ++j) { Node<K,V> e; if ((e = oldTab[j]) != null) { oldTab[j] = null; if (e.next == null) newTab[e.hash & (newCap - 1)] = e; else if (e instanceof TreeNode) ((TreeNode<K,V>)e).split(this, newTab, j, oldCap); else { // preserve order Node<K,V> loHead = null, loTail = null; Node<K,V> hiHead = null, hiTail = null; Node<K,V> next; do { next = e.next; if ((e.hash & oldCap) == 0) { if (loTail == null) loHead = e; else loTail.next = e; loTail = e; } else { if (hiTail == null) hiHead = e; else hiTail.next = e; hiTail = e; } } while ((e = next) != null); if (loTail != null) { loTail.next = null; newTab[j] = loHead; } if (hiTail != null) { hiTail.next = null; newTab[j + oldCap] = hiHead; } } } } } return newTab; }
“HashMap底层源码是什么”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注亿速云网站,小编将为大家输出更多高质量的实用文章!
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。