【问题标题】:understanding method comment for hash() method of HashMap class in java 8理解java 8中HashMap类的hash()方法的方法注释
【发布时间】:2016-08-01 22:16:48
【问题描述】:
 /**
     * Computes key.hashCode() and spreads (XORs) higher bits of hash
     * to lower.  Because the table uses power-of-two masking, sets of
     * hashes that vary only in bits above the current mask will
     * always collide. (Among known examples are sets of Float keys
     * holding consecutive whole numbers in small tables.)  So we
     * apply a transform that spreads the impact of higher bits
     * downward. There is a tradeoff between speed, utility, and
     * quality of bit-spreading. Because many common sets of hashes
     * are already reasonably distributed (so don't benefit from
     * spreading), and because we use trees to handle large sets of
     * collisions in bins, we just XOR some shifted bits in the
     * cheapest possible way to reduce systematic lossage, as well as
     * to incorporate impact of the highest bits that would otherwise
     * never be used in index calculations because of table bounds.
     */

static final int hash(Object key) {
    int h;
    return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}

以下是JDK 1.6的早期版本

/**
     * Applies a supplemental hash function to a given hashCode, which
     * defends against poor quality hash functions.  This is critical
     * because HashMap uses power-of-two length hash tables, that
     * otherwise encounter collisions for hashCodes that do not differ
     * in lower bits. Note: Null keys always map to hash 0, thus index 0.
     */
    static int hash(int h) {
        // This function ensures that hashCodes that differ only by
        // constant multiples at each bit position have a bounded
        // number of collisions (approximately 8 at default load factor).
        h ^= (h >>> 20) ^ (h >>> 12);
        return h ^ (h >>> 7) ^ (h >>> 4);
    }

有人能解释一下应用这种散列比在早期版本的 java 中所做的好处有什么好处吗?这将如何影响密钥分发的速度和质量,我指的是 jdk 8 中实现的新哈希函数,以及它是如何实现这一点以减少冲突的?

【问题讨论】:

标签: java data-structures hash hashmap


【解决方案1】:

hashCode 方法表现不佳的情况下,HashMap 的性能可能会急剧下降。例如,假设您的hashCode 方法只生成了一个16 位数。

这通过xoring 哈希码本身右移16 来解决问题。如果这个数字在此之前分布良好,它应该仍然是。如果它很糟糕,这应该改进它。

【讨论】:

  • 但是我们是如何实现右移 16 位的,为什么 32 不可以使这个效率更高。想知道我们是怎么圈出来的
  • 哈希码的大小是 32 位,16 位正好是哈希码大小的一半,右移 16 位并做异或是最佳方式,当大小时,将把大多数品种的哈希值hashmap 的值很低。很难在评论中解释清楚,但是您可以考虑如何将大多数品种带入哈希码中,而不管哈希图的大小(哈希图的大小增长为 2^n),它会点击为什么它是 16
【解决方案2】:

Here 很好地解释了 HashMap 在 Java 8 中的工作原理。下面是来自同一博客的 sn-p。

要理解这一点,我们首先需要了解索引是如何计算的:

将哈希码映射到数组中的索引。以最简单的方式,这可以通过对哈希码和数组长度执行模运算来完成,例如 hash(key) % n。使用模确保索引 i 始终介于 0 和 n 之间。

i = 哈希 %n;

对于 Java 中的 HashMap,索引 i 由以下表达式计算:

i = (n - 1) & 哈希;

在这个表达式中,变量n指的是表的长度,hash指的是key的哈希值。

由于我们使用位掩码 ((n - 1) & hash) 计算模数,因此任何 模数不会使用比 n - 1 的最高位高的位。 例如,给定 n = 32 和 4 个哈希码来计算。做的时候 直接取模,无需哈希码转换,所有索引都将 为 1. 碰撞率为 100%。这是因为掩码 31 (n - 1), 0000 0000 0000 0000 0000 0000 0001 1111,使任何位高于位置 5 在数字 h 中不可用。为了使用这些最高位,HashMap 将它们向左移动 16 个位置 h >>> 16 并以最低位 (h ^ (h >>> 16))。因此,得到的模数碰撞较少。

【讨论】:

    猜你喜欢
    • 2011-01-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-04-21
    • 2014-12-27
    相关资源
    最近更新 更多