
上一篇:消息队列 ActiveMQ 、RocketMQ 、RabbitMQ 和 Kafka 如何选择?
正文
& 按位与
| 按位或
^ 按位异或
~ 按位取反
除 ~ 以外,其余均为二元运算符。
Java 数据类型
Java整型数据类型有:byte、char、short、int、long。要把它们转换成二进制的原码形式,必须明白他们各占几个字节。
数据类型 所占位数
byte 8
boolean 8
short 16
int 32
long 64
float 32
double 64
char 16
int 类型占 4 个字节(byte)
一个字节 = 8bit(位)
一个 int 类型的数值占 32bit(位)
int i = 123;
10 进制 123 转为二进制后等于:1111011
负数对比
已知补码求原码
最高位如果是 1 的话(负数),那么除了最高位之外的取反,然后加 1 得到原码。
最高位如果是 0 的话(正数), 不变,正数的补码就是它的原码。
在计算机系统中,数值一律用补码来表示和存储。原因在于,使用补码,可以将符号位和数值域统一处理;同时,加法和减法也可以统一处理。此外,补码与原码相互转换,其运算过程是相同的,不需要额外的硬件电路。(摘自百度百科)
打个比方:2-1是怎么计算的?
计算公式:2-1=2+(-1);
2 的补码:00000010
-1 的补码:11111111
结果 00000001,最高位溢出()丢弃, 2-1 = 1。
& 按位与
&:如果相对应位都是 1,则结果为 1,否则为 0。
int A = 60;
int B = 13;
A & B = 12 ,即 00001100(省略了前面三组 00000000)
如何得到 12 的呢?
60 的补码为:00111100(省略了前面三组 00000000)
13 的补码为:00001101(省略了前面三组 00000000)
按位与后值为:00001100(省略了前面三组 00000000)
将其转换为十进制:12
在 boolean 类型的值上用法也如下:

| 按位或
|:如果相对应位都是 0,则结果为 0,否则为 1。
继续使用上面的例子:
int A = 60;
int B = 13;
A | B = 61 ,即 00111101(省略了前面三组 00000000)
如何得到 61 的呢?
60 的补码为:00111100(省略了前面三组 00000000)
13 的补码为:00001101(省略了前面三组 00000000)
按位或后值为:00111101(省略了前面三组 00000000)
将其转换为十进制:61
在 boolean 类型的值上用法也如下:

^ 按位异或
^:如果相对应位值相同,则结果为 0,否则为 1。
继续使用上面的例子:
int A = 60;
int B = 13;
A ^ B = 49 ,即 00110001(省略了前面三组 00000000)
如何得到 49 的呢?
60 的补码为:00111100(省略了前面三组 00000000)
13 的补码为:00001101(省略了前面三组 00000000)
按位异或后值为:00110001(省略了前面三组 00000000)
将其转换为十进制:49
在 boolean 类型的值上用法也如下:

~ 按位取反
~:按位取反运算符翻转操作数的每一位,即 0 变成 1 ,1 变成 0。
继续使用上面的例子:
int A = 60;
~A = -61 ,即 11000011(省略了前面三组 11111111)
如何得到 -61 的呢?
60 的补码为:00111100(省略了前面三组 00000000)
按位取反后值为:11000011(省略了前面三组 11111111)
将其转换为十进制:-61
<< 按位左移运算符
<<:按位左移运算符。左操作数按位左移右操作数指定的位数(在低位补 0)。
int A = 60;
A << 2 = 240 ,即 11110000(省略了前面三组 00000000)
如何得到 240 的呢?
60 的补码为:00111100(省略了前面三组 00000000)
按位左移 2 位后为:11110000(省略了前面三组 00000000)
转换为十进制为:240
左移运算符,num << 1,相当于 num 乘以 2(每左移一位就相当于乘以一个 2)。
>> 按位右移运算符
>>:按位右移运算符。左操作数按位右移右操作数指定的位数(如果该数为正数,则高位补 0 ,若为负数,则高位补 1)。
int A = 60;
A >> 2 = 15 ,即 00001111(省略了前面三组 00000000)
如何得到 15 的呢?
60 的补码为:00111100(省略了前面三组 00000000)
按位右移 2 位后值为:00001111(省略了前面三组 00000000)
转换为十进制为:15
右移运算符,num >> 1,相当于 num 除以 2(每右移一位相当于除以一个 2)。
>>> 按位右移补零操作符
>>:按位右移补零操作符。左操作数的值按右操作数指定的位数右移,移动得到的空位以零填充(忽略符号位)。
正数 >>> 的结果和 >> 一样,负数则天差地别,故下面例子为负数:
int A = -2;
-2 的补码为:11111110(省略了前面三组 11111111)
负数按位右移
A >> 1 = -1 ,即 11111111(省略了前面三组 11111111)
负数按位右移补零
A >> 1 = 2147483647
-2 补码:11111111 11111111 11111111 1111111
右移 1 位:_1111111 11111111 11111111 11111111
右移 1 位之后,最后一个 0 被覆盖掉,符号位空了一位(下划线_处),按照规则,忽略符号位补零,那么第一位(符号位)就是 0 了。
补零后:11111111 11111111 11111111 11111111
转换成十进制数为:2147483647 。
注意:不存在无符号 <<< 运算符。
由于数据类型所占字节是有限的,而位移的大小却可以任意大小,所以可能存在位移后超过了该数据类型的表示范围,于是有了这样的规定:
如果为int数据类型,且位移位数大于32位,则首先把位移位数对32取模,不然位移超过总位数没意义的。所以4>>32与4>>0是等价的。
如果为long类型,且位移位数大于64位,则首先把位移位数对64取模,若没超过64位则不用对位数取模。
如果为byte、char、short,则会首先将他们扩充到32位,然后的规则就按照int类型来处理。
位运算有什么用
旁白:文章写到一半差点魔怔,在它(魔怔)的边缘疯狂摩擦QAQ...
如果你觉得文章不错,欢迎在看、转发、赞赏一条龙,你的支持就是我最大的动力。

往期精彩回顾

朕已阅 
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/69902700/viewspace-3165872/ ,如需转载,请注明出处,否则将追究法律责任。