这个是我同学的面试题,当时我和他说的不清楚,于是就有了这篇文章。看到题目就知道这是Java7
的HashMap
的方法去计算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
,我们进行与运算的时候hash
和n-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
的范围内,这就是为什么和取模的效果一样。