什么是hashCode
哈希码产生的依据:哈希码并不是完全唯一的,它是一种算法,让同一个类的对象按照自己不同的特征尽量的有不同的哈希码,但不表示不同的对象哈希码完全不同。也有相同的情况,看程序员如何写哈希码的算法
哈希冲突
如果在代码中创建一个对象,直接使用hashCode方法,这个hashCode方法是object类的,目的是返回一个对象的哈希码,但是会出现一个问题,不同的对象也可能会得到相同的哈希码,这就出现了哈希冲突。
hashMap源码中决定将元素要放进桶的哪个下标位置的代码如下
p = tab[i = (n - 1) & hash]
有一种情况,两个哈希码低位相同,高位不同,但是高位在&运算下并没有太大意义,所以还是得到了相同的下标。那么该下标桶,key相同则覆盖value,哈希冲突大的情况下,就会一直往该下标桶添加元素,而其他下标桶却很空闲。
int hashCode1 = 117; // 01110101
int hashCode2 = 85; // 01010101
System.out.println(hashCode1 & 15);//01110101 & 1111 -> 0101
System.out.println(hashCode2 & 15);//01010101 & 1111 -> 0101
hashMap的hash算法提供了不同的解决方案。以下是hashMap源码
(h = key.hashCode()) ^ (h >>> 16)
将哈希码无符号右移16位,也就是说将原来的高位变为了低位,然后与原来的哈希码进行异或运算,得到了新的哈希码。这样减少了哈希冲突,使散列更加分布均匀。
以下是个人实现的hash运算,只无符号右移了4位。
int hashCode1 = 117; // 01110101
int hashCode2 = 85; // 01010101
hashCode1 = hashCode1 ^ (hashCode1 >>> 4); //01110101 ^ 0111 -> 01110010
hashCode2 = hashCode2 ^ (hashCode2 >>> 4); //01010101 ^ 0101 -> 01010000
System.out.println(hashCode1 & 15);//01110010 & 1111 -> 0010
System.out.println(hashCode2 & 15);//01010000 & 1111 -> 0000