Java源码的二进制骚操作-HashMap构造函数 发表于 2020-03-20 | 分类于 Java | 次 Java 源码的二进制骚操作-HashMap构造函数1. 问题:指定capacity构造hashmap,为什么经过一连串的移位跟或运算就能得到2的n次幂2. 目标:为了找到大于等于A的,最小的,2的n次幂3. 思路: 1234567891011比如为了找到大于等于10的,最小的,2的n次幂16对于一个数A将其转化为一串二进制,如10,1610 => 00000000 00000000 00000000 0000101016 => 00000000 00000000 00000000 00010000只需要将A的,最高位为1的,后面的二进制全部变为1,然后在+1就可以了如下:1、找最高位为1的地方:00000000 00000000 00000000 00001(最高位为1)0102、后面的二进制全部变为100000000 00000000 00000000 00001(最高位为1)1113、再+100000000 00000000 00000000 00010000 4. 源码,源码位置:HashMap.tableSizeFor方法123456789static 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;} 5. 分析123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263源码里面,一上来就减1,然后各种位移运算,接着就返回了。。。无妨,待我细细讲来这里假设cap = 10/**首先为什么要减1,因为目标是找到大于等于A的,最小的n次幂如果不减1,而刚好cap参数就是2的n次幂的时候,那就要引入if/else分支来判断,直接返回所以-1是为了后面的位移运算能兼容cap参数直接等于2的n次幂,和非2的n次幂,现在不理解没事,看完后面的再回来看就能理解了,换个cap参数试一下就知道**/1、int n = cap - 1;/**cap = 10,n = cap - 1 = 9;n的二进制为 00000000 00000000 00000000 00001(最高位为1)001第一次运算无符号右移一位,最高为为1的位像右移动了1位二进制为 00000000 00000000 00000000 00000100位移之后与原来的数做或运算,好,为什么是或运算因为1的所有或运算都等于1在最高位已经右移了一位的情况下,做或运算一定能得到,最高位连续两位为1如下:00000000 00000000 00000000 00001001:原来的数|:或操作00000000 00000000 00000000 00000100:右移错开了一位00000000 00000000 00000000 000011(最高位两位连续为1)00:或的结果**/2、 n |= n >>> 1;/**在有了最高位两位连续为1的情况下,再右移两位,做或运算,一定能得到,最高位四位连续为1**/3、 n |= n >>> 2;/**同理,在有了最高位四位连续为1的情况下,再右移四位,做或运算,一定能得到,最高位8位连续为1,这里由于cap=10,所以到了这里右移得到的数据全为0,与0或操作之后得到的数都等于原来的值,可以选个大点的cap值就知道了**/4、 n |= n >>> 4;/**在有了最高位8位连续为1的情况下,再右移8位,做或运算,一定能得到,最高位16位连续为1**/5、 n |= n >>> 8;/**在有了最高位16位连续为1的情况下,再右移16位,做或运算,一定能得到,最高位32位连续为1**/6、 n |= n >>> 16;//最后再做一些兼容运算7、 return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1; 6. 位操作是最适合计算机的,但读起来真的是反人类啊