HashMap——哈希值计算和组数下标计算

2 篇文章 0 订阅

要计算HashMap中对应的数组下标,必然要进行获取哈希值,HashMap对key的哈希值做了离散处理。

JDK 7

哈希值计算:


    /**
     * Retrieve object hash code and applies a supplemental hash function to the
     * result hash, 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.
     */
    final int hash(Object k) {
        int h = hashSeed;
        if (0 != h && k instanceof String) {
            return sun.misc.Hashing.stringHash32((String) k);
        }

        h ^= k.hashCode();

        // 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);
    }

下标计算:


    /**
     * Returns index for hash code h.
     */
    static int indexFor(int h, int length) {
        // assert Integer.bitCount(length) == 1 : "length must be a non-zero power of 2";
        return h & (length-1);
    }

JDK 8

哈希值计算:


/**
 * 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);
}

下标计算:(put方法中摘抄)

n = tab.length
i = (n - 1) & hash

哈希值计算:

  • JDK 7:使用哈希种子,将原哈希值和左移20位、左移12位、左移7位、左移4位的四个值,一起异或运算(^)。
  • JDK 8:将原哈希值和左移16位的值,一起异或运算(^)。

哈希种子(hashSeed),一个和实例有关的随机数,添加离散程度,可以被禁用,为0。通过vm参数 ‘-Djdk.map.althashing.threshold=7’,当数组容量大于7时,提供哈希种子。

JDK 7时,对key等于null时,是固定放在下标位0的位置,不参加哈希值计算,
到了JDK 8时,key等于null时,是在哈希值计算中处理,返回哈希值为0。最终结果一直,只是处理过程不一样。

下标计算:

算法一样。都是再数组长度减一后,做与运算(&)。因为配合数组长度位2的次方数,所以相当于length-1取余。

例子:

计算后的哈希值 x,length=16,下标10.

   x     : 0010 0011 1111 1100 0110 0010 0101 1010
length-1 : 0000 0000 0000 0000 0000 0000 0000 1111
   &
index    : 0000 0000 0000 0000 0000 0000 0000 1010
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值