Java位运算符

Java位运算符

今天在学习 HashMap 的时候,发现这么一段代码:

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);
}

方法的作用就是,输入一个数,如果该数为2的幂次方,那么将原数返回回去,如果不是,那么会返回另一个数,也会是2的幂次方。看完我就觉得我该好好看看位运算符了。

位运算符主要针对二进制进行运算,它包括了:“与”、“非”、“或”、“异或”、“左移”、“右移”和“无符号右移”,下面详细介绍每个位运算符。

使用的例子为:a = 60,b = 13;它们的二进制格式表示将如下:

A = 0011 1100
B = 0000 1101
-----------------
A&b = 0000 1100
A | B = 0011 1101
A ^ B = 0011 0001
~A= 1100 0011

“与”运算

“与”运算对应的符号是 “&”,如果相对应位都是1,则结果为1,否则为0

“或”运算

“或”运算对应的符号是 “|”,如果相对应位都是0,则结果为0,否则为1

“非”运算

“非”运算对应的符号是 “~”,按位取反运算符翻转操作数的每一位,即0变成1,1变成0

“异或”运算

“异或”运算对应的符号是 “^”,如果相对应位值相同,则结果为0,否则为1

“左移”运算

“左移”运算对应的符号是:”<<”,左操作数按位左移右操作数指定的位数。比如A << 2得到240,即 1111 0000,实际上在不超出数据范围的情况下,这种操作相当于左操作数乘以2的右操作数次幂,对于负数也依然成立。

“右移”运算

“右移”运算对应的符号是:”>>”,左操作数按位右移右操作数指定的位数,比如A >> 2得到15即 1111,实际上在不超出数据范围的情况下,这种操作相当于左操作数除以2的右操作数次幂。

如果左操作数是正数,运算相当于对2的右操作数次幂进行取模运算,如:7>>2=1;9>>10=0

如果左操作数是负数,情况不太意义,如:-7>>2=-2

“无符号右移”运算

“无符号右移”运算对应的符号是:”>>>”,按位右移补零操作符。左操作数的值按右操作数指定的位数右移,移动得到的空位以零填充,是针对无符号数的。

Java集合中设定容量大小的算法

回到我们最开始的那个算法上来。

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=8,则n初始化为7,7的二进制表示为 0111 (为了方便,省去很多不必要的0)后面的5个步骤为

0111 | 0011 = 0111 (移1位得到有操作数)
0111 | 0001 = 0111 (移2位得到有操作数)
0111 | 0000 = 0111 (移4位得到有操作数)
0111 | 0000 = 0111 (移8位得到有操作数)
0111 | 0000 = 0111 (移16位得到有操作数)

所以我们可以看出,当输入2的幂次方的数时,我们对其减一,得到的结果的二进制表示为最高位位为0,后面全为1,将这个二进制数再与自己无符号右移得到的结果进行或运算,都是还是等于自己的,再将结果加一,还是变回原样。

如果输入 cap=65,则n初始化为64,64的二进制表示为 1000000,后面的5个步骤为

1000000 | 0100000 = 1100000(移1位得到有操作数)
1100000 | 0011000 = 1111000(移2位得到有操作数)
1111000 | 0000111 = 1111111(移4位得到有操作数)
1111111 | 0000000 = 1111111(移8位得到有操作数)
1111111 | 0000000 = 1111111(移16位得到有操作数)

可以看出最后得到的二进制数都是全1的,因为 int 类型是32位的,所以这种操作,最后都能全1的二进制数,至于是多少位,依据输入数最高位所在的位判断,而这种二进制数加一之后得到的值肯定是2的幂次方,不得不说这种算法简洁而又高效,学习了!

判断数是否为2的幂次方

还有一种算法来判断一个数是否为2的幂次方

public static boolean isPowerOf2(int n) {
    return (n & -n) == n;
}

这个道理差不多,也是进行位运算,算法很高效。如果输入的是65,则其二进制表示为 1000001,而-65则是 11111111111111111111111110111111 (负数的补码),再按位与,得到结果为1,和原来的不一样,所以不是2的整数次方数。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值