JDK 8 中的 hashmap 是否在桶中的条目对象从阈值减少后再次调整自身大小。?

Does hashmap in JDK 8 resizes itself again after the entry objects in a bucket decreases from the threshold.?

我看到一个博客,其中在 JDK8 中给出了 hashmap 的更改和性能改进。

From JDK 1.8 onwards HashMap has introduced an improved strategy to deal with high collision rate. Since a poor hash function e.g. which always return location of same bucket, can turn a HashMap into linked list, i.e. converting get() method to perform in O(n) instead of O(1) and someone can take advantage of this fact, Java now internally replace linked list to a binary true once certain threshold is breached. This ensures performance or order O(log(n)) even in the worst case where a hash function is not distributing keys properly.

在JDK8中,我们都知道,每当达到一个阈值时,链表就会重新调整自己的大小为二叉树。我想知道当节点数小于阈值时,二叉树是否会将自身重新调整为链表。?

在一次采访中有人问我,我回答说,不,因为每次数字发生变化时它都不会不断调整自己的大小。我说得对吗?

参考博客:

  1. http://javarevisited.blogspot.com/2014/07/java-optimization-empty-arraylist-and-Hashmap-cost-less-memory-jdk-17040-update.html
  2. http://javarevisited.blogspot.com/2011/02/how-hashmap-works-in-java.html

这是 HashMap 来源中评论的一部分:

 * Because TreeNodes are about twice the size of regular nodes, we
 * use them only when bins contain enough nodes to warrant use
 * (see TREEIFY_THRESHOLD). And when they become too small (due to
 * removal or resizing) they are converted back to plain bins.  

再往下看,我看到了:

/**
 * The bin count threshold for using a tree rather than list for a
 * bin.  Bins are converted to trees when adding an element to a
 * bin with at least this many nodes. The value must be greater
 * than 2 and should be at least 8 to mesh with assumptions in
 * tree removal about conversion back to plain bins upon
 * shrinkage.
 */
static final int TREEIFY_THRESHOLD = 8;

/**
 * The bin count threshold for untreeifying a (split) bin during a
 * resize operation. Should be less than TREEIFY_THRESHOLD, and at
 * most 6 to mesh with shrinkage detection under removal.
 */
static final int UNTREEIFY_THRESHOLD = 6;

所以问题的答案是"yes and no"。当大小低于 相同 阈值时它不会自行调整大小,但当它低于不同的阈值时它会调整大小。

我不明白为什么面试会问你这个问题——你应聘的公司真的希望你记住Java库的源代码吗?

个体 bin/bucket 中存在的二叉树节点将在调整大小或删除过程中取消树化。但是,如果删除关联的地图元素,内部 Table 的容量、阈值和整体大小不会缩小。

注意:Java8以后HashMap使用按位运算符实现2的幂扩展,以保持基本操作的恒定时间性能。每当地图大小超过阈值时,它就会重新散列。在此 resize/expansion 期间,容器中存在的树将被拆分为 loBit/hiBit 树,如果树太小,则将相同的树分解,将 hiBit 节点头移动到新的 Table 索引,其值为两个偏移量