【Java】hash& (n-1)为什么和取模效果一样?

这个是我同学的面试题,当时我和他说的不清楚,于是就有了这篇文章。看到题目就知道这是Java7HashMap的方法去计算Key值所在HashMap的位置

解析

我们看到底是谁调用了这个方法。

final int hash(Object k) {
    
    
    int h = 0;
    if (useAltHashing) {
    
    
        if (k instanceof String) {
    
    
            return sun.misc.Hashing.stringHash32((String) k);
        }
        h = hashSeed;
    }

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



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



public V put(K key, V value) {
    
    
	...
	int hash = hash(key);
	int i = indexFor(hash, table.length);
	...
}

就是说 hash(Object k) 这个方法返回给我们一个 int 值。然后我们通过indexfor(int h,int length)这个方法去计算我们哈希桶的下标值。

首先我们先了解什么是n

n表示哈希桶的长度,就是你hashmap这个实例的容量(默认是16,每次扩容翻一倍)这个很好理解,那为什么要减1,我们知道16的二进制是10000,减1后就变成1111,这样我们有了一个二进制全部为1的数后就可以进行&运算。

什么是&运算

1 & 1 = 1  
1 & 0 = 0  
0 & 0 = 0 

什么是hash

hash方法返回了一个int值,当我们转化成二进制的时候假设是new Object(),他的hashCode()方法返回了1063710268,转换为二进制是111111011001101110111000111100,我们进行与运算的时候hashn-1,即hash和 2^(m-1)的数,即hash和 二进制全为1的数进行&运算

举例子

## 假设我的哈希桶的长度是默认长度16
## 所以我的n - 1 即为 15
## 所以我的二进制表示为 1111
## 假设我hash值是 111111011001101110111000111100
## 即
111111011001101110111000111100 ## hash
000000000000000000000000001111 ## n-1
000000000000000000000000001100 ## 我的indexfor的值就为1100 即12

那么也就是说我这个new Object() 会被插在第12位,这个完全取决于哈希桶的长度。就算你最后几位都是1,你插的位置还是在n-1的范围内,这就是为什么和取模的效果一样。

猜你喜欢

转载自blog.csdn.net/weixin_42126468/article/details/104958536