【问题标题】:Java HashMap array sizeJava HashMap 数组大小
【发布时间】:2017-08-13 22:56:06
【问题描述】:

我正在阅读Java 8 HashMap的实现细节,谁能告诉我为什么Java HashMap的初始数组大小具体是16? 16岁有什么特别之处?为什么总是二的力量?谢谢

【问题讨论】:

  • 你对16有什么看法?一个非常性感的号码

标签: java oop collections java-8 hashmap


【解决方案1】:

2 的幂无处不在的原因是,当用二进制表示数字时(就像它们在电路中一样),某些 2 的幂的数学运算更简单、更快(想想 10 的幂的数学是多么容易)是我们使用的十进制系统)。例如,多阳离子在计算机中不是一个非常有效的过程 - 电路使用的方法类似于您将两个数字与多个数字相乘时使用的方法。乘以或除以 2 的幂需要计算机将位移动到左边进行乘法或向右移动进行除法。

至于为什么 HashMap 是 16? 10 是动态增长结构的常用默认值(任意选择),而 16 并不遥远 - 但它是 2 的幂。

对于 2 的幂,您可以非常有效地进行取模。n % d = n & (d-1) 当 d 是 2 的幂时,取模用于确定项目映射到内部数组中的哪个索引 - 这意味着它经常出现在一个Java HashMap。模数需要除法,这也比使用bitwise and 运算符效率低得多。你可以通过阅读一本关于数字逻辑的书来说服自己。

bitwise and 以这种方式处理 2 的幂的原因是因为 2 的每个幂都表示为设置为 1 的单个位。假设该位是 t。当您从 2 的幂中减去 1 时,您将 t 以下的每个位设置为 1,并将 t(以及 t)以上的每个位设置为 0。Bitwise and 因此从数字 n 中保存位置 t 以下的所有位的值(如上所述),并将其余设置为 0。

但这对我们有什么帮助?请记住,除以 10 的幂时,您可以计算 1 后面的零的数量,并从被除数的最低有效位开始取该位数以找到余数。示例:637989 % 1000 = 989。类似的属性适用于只有一位设置为 1,其余设置为 0 的二进制数。示例:100101 % 001000 = 000101

【讨论】:

  • 非常感谢您的出色解释。除此之外,它是否必须对负哈希码做任何事情?如果我的哈希函数的哈希码返回负值会怎样?它有重要意义还是无关紧要?
  • 你仍然会得到两个数字的模数。如果您只是使用 Java 的模运算符,您可以得到一个带有负除数的负数,这将导致 ArrayOutOfBoundsIndexException,但如果您对此进行更正,您将得到与 bitwise and 方法相同的结果。
【解决方案2】:

选择hash & (n - 1)modulo 还有一件事,那就是负哈希。 hashcode 是 int 类型,当然也可以是负数。对负数取模(在 Java 中)也是负数,而 & 不是。

【讨论】:

    【解决方案3】:

    另一个原因是您希望阵列中的所有插槽都同样可能被使用。由于 hash() 均匀分布在 32 位上,如果数组大小没有划分到散列空间中,那么就会有余数导致较低的索引被使用的机会略高。理想情况下,不仅是哈希,而且 (hash() % array_size) 是随机且均匀分布的。

    但这仅对于散列范围较小的数据(如字节或字符)才真正重要。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-08-01
      • 1970-01-01
      • 1970-01-01
      • 2020-12-09
      • 2010-12-11
      • 2018-02-14
      • 2011-03-03
      相关资源
      最近更新 更多