java - OpenJDK的rehashing机制

标签 java hashmap bit-manipulation hash openjdk

http://www.docjar.com/html/api/java/util/HashMap.java.html 上找到此代码在搜索 HashMap 实现之后。

  264       static int hash(int h) {
  265           // This function ensures that hashCodes that differ only by
  266           // constant multiples at each bit position have a bounded
  267           // number of collisions (approximately 8 at default load factor).
  268           h ^= (h >>> 20) ^ (h >>> 12);
  269           return h ^ (h >>> 7) ^ (h >>> 4);
  270       }

有人可以阐明这一点吗?评论告诉我们为什么这段代码在这里,但我想了解这如何改善错误的散列值以及它如何保证位置的数量有限碰撞。这些魔数(Magic Number)是什么意思?

最佳答案

为了使它有意义,它必须与对 HashMap 如何将事物分配到桶中的理解相结合。这是选择桶索引的简单函数:

static int indexFor(int h, int length) {
    return h & (length-1);
}

因此您可以看到,在默认表大小为 16 的情况下,实际上只有哈希的 4 个最低有效位对分配存储桶很重要! (16 - 1 = 15,用 1111b 掩盖哈希)

如果您的 hashCode 函数返回,这显然是个坏消息:

10101100110101010101111010111111

01111100010111011001111010111111

11000000010100000001111010111111
//etc etc etc

这样的哈希函数不可能以其作者可见的任何方式“坏”。但是,如果您将它与 map 分配桶的方式结合起来,boom,MapFail(tm)。

如果您记住 h 是一个 32 位数字,那么它们根本就不是魔数(Magic Number)。它系统地将数字的最高有效位向右异或到最低有效位。这样做的目的是,当以二进制形式查看时,“跨越”它的任何地方出现的数字“差异”在最低有效位中变得可见。

冲突变得有界,因为具有相同相关 LSB 的不同数字的数量现在明显有界,因为二进制表示中任何地方出现的任何差异都被压缩到对存储重要的位中。

关于java - OpenJDK的rehashing机制,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7922019/

相关文章:

c - 将位域打包成字节的 C 预处理器宏?

bit-manipulation - 位操作的时间复杂度

c - 按位运算符 XOR

java - 无法在 App Engine 上初始化类,可在 dev_appserver 上运行

java - 使用 Eclipse Kepler 的包目标使用 Maven 构建创建的重复 WEB-INF 文件夹

java - 为什么 HashMap 快速失败只是因为它提供了一种迭代其键的方法?

java - 为什么这个 hashmap 有两次相同的键?

java - 使用泛型的 HashMap

java - 有更简单有效的方法来做到这一点吗?

java - 使用 charAt 和 while 循环 Java 查找字符串中的字母