关于 treeifyBin

替换给定哈希值的bin中的所有链接节点,除非表太小,在这种情况下,会调用 resize 调整大小。

treeifyBin方法,应该可以解释为:把容器里的元素变成树结构。当HashMap的内部元素数组中某个位置上存在多个hash值相同的键值对,这些Node已经形成了一个链表,当该链表的长度大于等于9(为什么是9?TREEIFY_THRESHOLD默认值为8呀?

源码

1、treeifyBin

  1. /**
  2. * Replaces all linked nodes in bin at index for given hash unless
  3. * table is too small, in which case resizes instead.
  4. */
  5. final void treeifyBin(Node<K,V>[] tab, int hash) {
  6. int n, index; Node<K,V> e;
  7. if (tab == null || (n = tab.length) < MIN_TREEIFY_CAPACITY)
  8. resize();
  9. else if ((e = tab[index = (n - 1) & hash]) != null) {
  10. TreeNode<K,V> hd = null, tl = null;
  11. do {
  12. TreeNode<K,V> p = replacementTreeNode(e, null);
  13. if (tl == null)
  14. hd = p;
  15. else {
  16. p.prev = tl;
  17. tl.next = p;
  18. }
  19. tl = p;
  20. } while ((e = e.next) != null);
  21. if ((tab[index] = hd) != null)
  22. hd.treeify(tab);
  23. }
  24. }

2、treeifyBin 源码注释

  1. /**
  2. * Replaces all linked nodes in bin at index for given hash unless
  3. * table is too small, in which case resizes instead.
  4. */
  5. /**
  6. * tab:元素数组
  7. * hash:hash值(要增加的键值对的key的hash值)
  8. */
  9. final void treeifyBin(Node<K,V>[] tab, int hash) {
  10. // 定义辅助变量
  11. int n, index; Node<K,V> e;
  12. /*
  13. * 如果元素数组为空 或者 数组长度小于 树结构化的最小限制
  14. * MIN_TREEIFY_CAPACITY 默认值64
  15. */
  16. if (tab == null || (n = tab.length) < MIN_TREEIFY_CAPACITY)
  17. // 如果元素数组长度小于这个值,Java 的开发人员认为此时 tab 太小
  18. // 没有必要过早去进行结构转换,调用 resize 扩容即可。
  19. // 当一个数组位置上集中了多个键值对,那是因为这些 key 的 hash 值和数组长度取模之后结果相同
  20. //(并不是因为这些key的hash值相同)
  21. // 因为 hash 值相同的概率不高,所以可以通过扩容的方式,来使得最终这些 key 的 hash 值在和 新的数组长度-1 取模之后,拆分到多个数组位置上。
  22. resize();
  23. // 如果元素数组长度已经大于等于了 MIN_TREEIFY_CAPACITY,那么就有必要进行结构转换了
  24. // 根据hash值和数组长度进行取模运算后,计算红黑树根节点位置索引,判断该索引位置是否已经存放了元素。
  25. else if ((e = tab[index = (n - 1) & hash]) != null) {
  26. // 该索引位置为空,new 一个红黑树的根节点出来
  27. TreeNode<K,V> hd = null, tl = null;
  28. do {
  29. // 将链表转换为红黑树
  30. TreeNode<K,V> p = replacementTreeNode(e, null);
  31. // 如果尾节点为空,说明还没有根节点
  32. if (tl == null)
  33. // 首节点(根节点)指向 当前节点
  34. hd = p;
  35. // 尾节点不为空,以下两行是一个双向链表结构
  36. else {
  37. // 当前树节点的 前一个节点指向 尾节点
  38. p.prev = tl;
  39. // 尾节点的 后一个节点指向 当前节点
  40. tl.next = p;
  41. }
  42. // 把当前节点设为尾节点
  43. tl = p;
  44. // 遍历链表,重复以上步骤
  45. } while ((e = e.next) != null);
  46. // 到目前为止 也只是把 Node 对象转换成了 TreeNode 对象,把单向链表转换成了双向链表
  47. // 把转换后的双向链表,替换原来位置上的单向链表
  48. if ((tab[index] = hd) != null)
  49. hd.treeify(tab);
  50. }
  51. }

https://blog.csdn.net/weixin_42340670/article/details/80503863

问题