HashMap源码分析(三)hash

这个方法的移位太复杂,有些难看懂,就看看文档上是怎么说的:


 /**
     * 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.
     */
大致意思是这样的:
使用一个hash方法用来改善原先hashCode方法低质量的问题。
这个是很关键的,因为HashMap使用的数组长度是2的次幂,在低位相同的话会产生碰撞。
至于null值,他一直就是放在数组的第一个的


带着这个注释,我们来看看他是怎么通过hash方法来改善HashCode的低质量问题的,怎么降低低位的相同情况,尽量减少碰撞。


1.先来分析一下map中数组的长度length。这个长度是规定要2的次幂的,这就有一个特点,将长度转化成二进制后,不管是多少,总是有一个位上是1,然后其他位上全是0。
这个时候length-1,这个位之后的数字就全是1了。比如过64,二进制是0100 0000,那么他减一就是0011 1111。length先说到这里。
2.再来看下hash方法的实现
static int hash(int h) {       
        h ^= (h >>> 20) ^ (h >>> 12);
        return h ^ (h >>> 7) ^ (h >>> 4);
    }

实在是太复杂了,测试一下把。

public class HashMapSource_hash {
	public static void main(String[] args) {
		transform(64);
		transform(64+32+16);
		transform(1+2+4+8);
	}
	static void transform(int h){
		System.out.println(Integer.toBinaryString(h)+"-->"+Integer.toBinaryString(hash(h)));
	}
	static int hash(int h) {
        h ^= (h >>> 20) ^ (h >>> 12);
        return h ^ (h >>> 7) ^ (h >>> 4);
    }
}

打印结果是这样的:

1000000-->1000100
1110000-->1110111
1111-->1111
这个方法的作用大致就是让低位0多的数在低位也得到几个1,这样有什么好处呢?

结合1来看,length-1的值是全是1的,这样2个进行&运算

如果length比较小,比如说是4,那么length-1的二进制为0000 0011,对于一些hashCode稍微高一点的数,如64.128,他们跟length-1与,得到的都是0,这样就发生了冲撞。这个&的好处就是既保证了速度,又保证了计算后得到的值是在length之内的。

indexFor方法做的就是这个事。

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

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

再来看看jdk1.8的hash方法

static final int hash(Object key) {
        int h;
        return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
    }
这里传递的是一个对象,比之前也简洁了很多

如果是空,返回0,如果不是空,返回hashCode与上hashCode无符号右移16位

hash是int类型的,int类型的最大值的二进制是31个1加上前面一个0,无符号右移16位就是舍弃了它一半的低位,把高位给搬到低位来了


这个方法要做的事就如下图:





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值