zl程序教程

您现在的位置是:首页 >  后端

当前栏目

Java 位运算符

JAVA 运算符
2023-09-14 09:05:10 时间

&:按位与。当两位同时为1时才返回1。
|:按位或。只要有一位为1即可返回1。
~:按位非。单目运算符,将操作数的每个位(包括符号位)全部取反。
^:按位异或。当两位相同时返回0,不同时返回1。
<<:左移运算符。

:右移运算符。

:无符号右移运算符。
注(上面所说的两位相同,指的是参与运算的两位整数的补码,也就是存储在计算机中的形式)
一般来说,位运算符只能操作整数类型的变量或值。

要想搞清楚这几个运算符是如何运算的,首先要弄明白几个概念。
我们知道数据在计算机中的存储形式都是二进制,整数自然也是这样。
这里涉及几个概念

原码、反码、补码。
原码就是将数字转换成二进制。
反码就是将原码的每位取反(如果是0,那就变成1。如果是1,那就变成0。符号位不变)。
补码就是在反码的基础上+1。

原码其实就是为了方便人类去看,补码是数字在计算机中存在的形态。
所以上面我们所说的运算符其实都是对数字的补码进行运算。
不太明白的请看这里关于原码,反码,补码的介绍

下面举个例子(我们用8位来表示,最前面一位表示符号位)
int a = 3;
原码:0000 0011
反码:0000 0011
补码:0000 0011
发现没,正数的原码,反码,补码都是一样的。其实反码跟补码都是为负数设计的。
int b = -3;
原码:1000 0011
反码:1111 1100
补码:1111 1101
可以看到,负数的原码到反码是各位取反(这里说的取反就是0变1,1变0)符号位不变。
反码到补码直接+1;

& 同为1则为1 否则为0
举个栗子:
5&9
5 补码 0000 0101
9 补码 0000 1001
结果 0000 0001
也就是1;

| 一位为1 则返回1
5|9
5 补码 0000 0101
9 补码 0000 1001
结果 0000 1101
也就是13;

~ 将操作数的每位取反
~-5
-5 补码 1111 1011
取反 0000 0100
结果也就是4;

^ 两位相同时返回0,不同时返回1
5^9
5 补码 0000 0101
9补码 0000 1001
结果 0000 1100
也就是12;

<<:左移运算符 将操作数的二进制码整体左移指定位数,右边空出的以0填充
-5<<2
首先算出-5的补码
1111 1011
左移两位 1110 1100 (将前面两位砍掉,整体左移,后面增加两位0。)
现在得到的是补码。
我们还要将补码转为原码。
其实就是原码->补码的反过程
先-1得到反码
1110 1011
然后取反得到原码
1001 0100
结果
-20;

:右移运算符 将操作数的二进制码整体右移指定位数,左边空出的以符号位填充(如果是正数,就是以0填充。如果是负数,就是以1填充。)
-5>>2
-5的补码
1111 1011
右移两位得到
1111 1110
再转为原码
1000 0010
结果
-2;

无符号右移运算符 将操作数的二进制码整体右移指定位数,左边空出来的位总是以0填充。
-5>>>2
1111 1011
右移两位,空出来的以0填充,所以得到的结果总是正数
0011 1110
而且大的惊人 2的30次方-2 1073741822;

注 关于移位运算还要遵循以下几个规则
对于低于Int类型(如byte、short、char)的操作数总是先自动类型转换为int类型后再移位。
对于Int类型的整数移位a>>b,当b>32时,系统会用b对32求余(因为int类型只有32位),得到的结果才是真正移位的位数。例如,a>>33和a>>1的结果是完全一样的,而a>>32和a相同。
对于long类型的整数移位a>>b,当b>64时,总是先用b对64求余(因为long类型是64位),得到的结果才是真正移位的位数。
当进行位移运算时,只要被移位的二进制码没有发生有效位的数字丢失(对于正数而言,通常指被移出的位全部都是0),可以发现左移n位就相当于乘以2的n次方,右移n位则是除以2的n次方。不仅如此,进行移位运算不会改变操作数本事,只是得到了一个新的运算结果,而原来操作数本事是不会改变的。