【集合-HashMap】HashMap中sizeForTable,hash()算法中的位运算

HashMap中位运算的运用可以说是神乎其神,也很难理解,接下来让我带你理解以下三种位操作,作者不做标题党,图文并茂你一定能看懂,欢迎交流学习

- tableSizeFor()方法,根据传入容量返回一个>=cap的最小二的整数次幂的数

static final int tableSizeFor(int cap) {
        int n = cap - 1;
        n |= n >>> 1;
        n |= n >>> 2;
        n |= n >>> 4;
        n |= n >>> 8;
        n |= n >>> 16;
        return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
    }

如何实现,这里结合一个栗子cap=10画图给你解释:(这里基本的位运算就不解释了)

首先我们明白一点,2的整数次幂的数,最高位是1,其余位都是0,例如16的二进制位:10000,那么15就是1111,所以反复或的操作就是不断地把每个位数都变成1,最后+1就变成了最近的二的整数次幂的数

在这里插入图片描述
第一次或操作:向右移动一位,最高有效位1也会向右移动一位,我们知道或操作有1就变成1,所以最高两位有效位都会变成1
在这里插入图片描述
第二次或操作:当再向右移动两位,相当于把第一步的高两位向后移动两位,所以或运算后,四位都是1

此时已经完成操作了,再移动四位后,结果不变(你可以尝试画一下),

最多移动16位就能完成操作,是因为int4个子节,32位,最多移动高16位到低16位就能完成操作

所以当位运算操作完之后,(n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;这里如果不超过最大值就返回n+1,例子中返回15+1 = 16,所以这就是sizeForTable()的算法

- 取模运算(n - 1) & hash

常用的hash函数有:直接定址,数字分析,等等(数据结构应该都学过),HashMap中使用的是初留取余法,就是取模运算,再HashMap底层使用了位运算实现取模操作,即(n - 1) & hash = hash % n,n表示桶也就是数组的长度

位运算实现取模操作有个前提,n必须是二的整数次幂,也就回答了为什么数组容量必须是二的整数次幂

同样,我用一个栗子结合图告诉你原理:a%b=a&(b-1)假设a=10,b=8

在这里插入图片描述
所以我们想取余数,就是得到移出来的三位,也就是原来1010的后三位,所以接下来求后三位,首先我们先知道一个特性:一个数和1做与运算都是本身:0&1=0,1&1=1,所以我们将b,也就是一个n位2的整数次幂的数-1就会得到n-1位全1的数,例如16:10000,15:1111

结合这两个特性,就可以得到余数
在这里插入图片描述

- Hash()算法,扰动函数

static final int hash(Object key) {
        int h;
        return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
    }

这里hash函数根据key获取散列地址,h = key.hashCode()) ^ (h >>> 16操作意义在哪?

简单来说就是让元素在散列表中分布的更散列,减少冲突的可能性

上面的方法中,我们可以看到hash值会和长度做位运算,当数组的长度很短时,只有低位数的hashcode值能参与运算。而让高16位参与运算可以更好的均匀散列,减少碰撞,进一步降低hash冲突的几率。并且使得高16位和低16位的信息都被保留了。

大家可以打开hashmap的源码,找到hash方法,按住ctrl点击方法里的hashcode,跳转到Object类,然后可以看到hashcode的数据类型是int。int为4个字节,1个字节8个比特位,就是32个比特位,所以16是因为32对半的结果,也就是让高的那一半也来参与运算

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值