为什么 resize 实现方式是这样的?

26

我对添加新的键值对时重新构建HashMaps有几个问题。我将基于以下事实提出问题(它们适用于Oracle JVM,不确定其他JVM是否正确):

  1. 每次当你将HashMap扩大到大于阈值(阈值=loadFactor*numberOfEntries)时,Resize会重新构建HashMap,使其具有更大的内部表数组大小。无论新创建的Entry放在哪个存储桶中 - Map仍然会变得更大。即使所有条目都进入一个桶中(即它们的键的hashCode()返回相同的编号)。
  2. HashMap删除数据后不会缩小。即使从HashMap中删除了所有键,它的内部表大小也不会改变。

现在是问题:

  1. 这些事实是否正确?

如果是这样的话:

  1. 为什么要实现这种方式的缩放?增加内部表的大小即使明显不必要是有意图的吗?还是一个错误?
  2. 为什么不会缩小?
1个回答

25

是的,这些事实是正确的。

  1. 检测是否“明显不必要”需要很长时间,而且几乎总是多余的,因为所有键具有相同哈希码的情况很少。简而言之,你为了在一个极其罕见的情况下节省一些工作,而为每个人付出了显著的代价(跟踪一个特定哈希码有多常见),这将比它所节省的更加昂贵。
  2. 因为删除操作较少发生,并且通常后面是用新的内容填充map。如果你想使用较小的表重新开始map,则可以将其分配给new HashMap并让旧表被垃圾收集。

哇,那很合理,谢谢!我可以再问一个问题吗?为什么我们不能在添加表桶时增加哈希映射,而是在添加条目时增加呢? - deemson
3
那个问题没有意义。"Table buckets are added"是"the hashmap growing"的同义词。哈希映射表的用户无法“添加表桶”,只有在有更多条目时才会添加表桶。 - Louis Wasserman
抱歉,“table buckets are added” 的意思是“填充内部表数组”。我的意思是,当所有表数组元素都不为 null(或其中一部分)时,为什么我们不调整地图的大小呢? - deemson
3
当添加条目时进行调整大小,实际上是在平均每个存储桶中的条目数超过一定数量时调整表的大小。实际情况下,原始表中的每个存储桶会被分成两个新表中的存储桶,每个新存储桶大约有一半的旧存储桶中的条目。非空存储桶的数量并不重要,重要的是每个存储桶中的平均条目数量。 - Louis Wasserman

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接