在java的源码中我们会经常看到一些这些特殊的运算,了解这些运算的规则可以帮助我们更好的理解代码的意义。
以下我整理的是一些运算的含义,也是边整理边学习,希望对你们有用,如有错误之处还请各位大佬指正,谢谢。
目录
|(或运算符)
| 是针对二进制的二目运算符。运算规则:两个二进制数值如果在同一位上只要有一个1,则结果中该位为1,否则为0。
比如:1000 | 101 = 1101 .
下面是一些java代码举例。
java十进制运算 | 二进制运算 | 二进制运算结果 | 十进制运算结果 |
1 | 2 | 1 | 10 | 11 | 3 |
2 | 1 | 10 | 1 | 11 | 3 |
1 | 3 | 1 | 11 | 11 | 3 |
2 | 3 | 10 | 11 | 11 | 3 |
1 | 4 | 1 | 100 | 101 | 5 |
2 | 4 | 10 | 100 | 110 | 6 |
3 | 4 | 11 | 100 | 111 | 7 |
1 | 5 | 1 | 101 | 101 | 5 |
2 | 5 | 10 | 101 | 111 | 7 |
3 | 5 | 11 | 101 | 111 | 7 |
4 | 5 | 100 | 101 | 101 | 5 |
对于代码中的布尔类型运算,则表示两边有一个为true则结果为true,需要注意的是,运算符两边都会计算的。即使 | 前面是false,也会计算 | 后面的表达式。
例如:
System.out.println(true | false); // true
System.out.println(true | true); // true
System.out.println(false | true); // true
System.out.println(false | false); // false
对于十进制数来说,只要两个数有一个奇数,则结果一定是奇数,只有两个数都是偶数,结果才会是偶数。
奇数 | 奇数 = 奇数
奇数 | 偶数 = 奇数
偶数 | 奇数 = 奇数
偶数 | 偶数 = 偶数
&(与运算符)
& 是是针对二进制的二目运算符。两个二进制数值如果在同一位上都是1,则结果中该位为1,否则为0 。
比如: 10010 & 110 = 00010 .
下面是一些java代码举例。
java十进制运算 | 二进制运算 | 二进制运算结果 | 十进制运算结果 |
1 & 2 | 1 & 10 | 00 | 0 |
2 & 1 | 10 & 1 | 00 | 0 |
1 & 3 | 1 & 11 | 01 | 1 |
2 & 3 | 10 & 11 | 10 | 2 |
1 & 4 | 1 & 100 | 000 | 0 |
2 & 4 | 10 & 100 | 000 | 0 |
3 & 4 | 11 & 100 | 000 | 0 |
1 & 5 | 1 & 101 | 001 | 1 |
2 & 5 | 10 & 101 | 000 | 0 |
3 & 5 | 11 & 101 | 001 | 1 |
4 & 5 | 100 & 101 | 100 | 4 |
对于布尔类型的运算,需要&两边都是true,结果才会是true。
System.out.println(true & false); // false
System.out.println(true & true); // true
System.out.println(false & true); // false
System.out.println(false & false); // false
对于十进制来说,当两个数都是奇数时,进行&与运算,则结果一定是奇数,其余情况结果要么是0要么是 偶数。
^(异或运算符)
^是针对二进制的二目运算符。运算规则:两个二进制数,如果在同一位上数值相同,则该位结果为0,否则为1。
比如: 10100 ^ 101 = 10001 .
下面是一些java代码举例。
java十进制运算 | 二进制运算 | 二进制运算结果 | 十进制运算结果 |
1 ^ 2 | 1 ^ 10 | 11 | 3 |
2 ^ 1 | 10 ^ 1 | 11 | 3 |
1 ^ 3 | 1 ^ 11 | 10 | 2 |
2 ^ 3 | 10 ^ 11 | 01 | 1 |
1 ^ 4 | 1 ^ 100 | 101 | 5 |
2 ^ 4 | 10 ^ 100 | 110 | 6 |
3 ^ 4 | 11 ^ 100 | 111 | 7 |
1 ^ 5 | 1 ^ 101 | 100 | 4 |
2 ^ 5 | 10 ^ 101 | 111 | 7 |
3 ^ 5 | 11 ^ 101 | 110 | 6 |
4 ^ 5 | 100 ^ 101 | 001 | 1 |
对于布尔类型运算,因为true=1,false=0,所以如果两边相同则结果为0,也就是false。
System.out.println(true ^ false); // true
System.out.println(true ^ true); // false
System.out.println(false ^ true); // true
System.out.println(false ^ false); // false
对于十进制来说,如果两个数都是奇数,或者两个数都是偶数,则^异或结果一定是偶数,其余情况则为奇数,如果两个数相同,则结果一定是0。
|| (或逻辑运算符)
逻辑运算符。当 || 两边有一个表达式结果为true时,结果就为true,反之为false。而且当第一个表达式结果为true时不计算第二个表达式。
&& (且逻辑运算符)
逻辑运算符。当且仅当两边表达式都是true时结果才为true,反义false。如果第一个表达式结果为false,不进行第二个表达式计算。
>> (右移运算)
首先理解一下机器编码(二进制)。各种数值在计算机中表示的形式成为机器数,其特点是采用二进制计数制,数的符号用0和1表示。正负符号在最高位,0:正,1:负。
以8位机器字节长为例,所以十进制0使用机器数表示为0 0000000或者1 0000000,+1为0 0000001,-1为1 0000001 。
机器数的码制分为:原码、反码、补码、移码表示。例如:
+5的四个码制表示法如下: 原码:0 0000101 反码:0 0000101 补码:0 0000101 移码:1 0000101 | -5的四个码制表示法如下: 原码:1 0000101 反码:1 1111010 补码:1 1111011 移码:0 1111011 |
由上可以看出,正数的原码、反码、补码相同,负数的反码为原码的绝对值求反(也就是符号不变,其余取反),负数的补码为其反码的末位加1 。移码都是其补码的符号取反。
然后说一下位运算。
X >> y:表示将X值右移y位。正数和负数右移的处理过程不同,正数是直接右移,则高位(最左边)补y个0。
负数是先求反码,再求补码,然后右移两位,最高位补y个1。再求反码,最后再求其原码。
以32位举例。
正数右移两位:38 >> 2
38的原码:00000000 00000000 00000000 00100110(首位0代表符号+)
右移两位:_ _ 000000 00000000 00000000 00001001
左边补两个0,得到:00000000 00000000 00000000 00001001
结果为:9(十进制)
负数右移两位:-38 >> 2
-38的原码: 10000000 0000000 0000000 00100110 (首位1表示负号-)
反码: 11111111 1111111 1111111 11011001 (符号位不变,其余为取反)
补码: 11111111 1111111 1111111 11011010 (反码的末位+1)
右移2位:_ _11111111 11111111 11111111 110110
补码左边添两个1,得到:11111111 1111111 1111111 11110110
反码:11111111 11111111 11111111 11110101 (补码的末位-1)
原码:10000000 00000000 00000000 00001010 (反码的符号位不变,其余为取反)
结果为:-10(十进制)
<<(左移运算)
X<<y(常数): 向左移动y位(顶点在哪个方向就往哪个方向移动),无论正负数低位(最右边)都补y个0。
正数向左移3位:38 << 3
原码:00000000 0000000 0000000 00100110
向左移三位,右边补三个0:00000 00000000 00000000 00100110 000
结果:304
负数向左移3位:-38 << 3
原码:10000000 0000000 0000000 00100110
反码:11111111 11111111 11111111 11011001
补码:11111111 11111111 11111111 11011010
左移三位,右边补三个0
补码:11111 11111111 11111111 11011010 000
反码:11111 11111111 11111111 11011001 111
原码:10000 00000000 00000000 00100110 000
结果:-304
对于10进制来说,左移可以理解为2的幂次方,比如 :
- 38 << 3 就等于 38 乘以 2的3次方,就等于38 * 8 = 304。
- 5 << 5 就等于 5 乘以 2的5次方,就等于5 * 32 = 160 。
>>>(无符号右移运算)
表示无符号右移x位,所谓无符号是与>>x对比,该操作在移动后,无论正负数高位(最左边)都补0。
正数右移两位:38 >>> 2
原码: 00000000 00000000 00000000 00100110
右移两位,最左边添两个0:00 00000000 00000000 00000000 001001
结果:9
负数右移两位:-38 >>> 2
原码:10000000 0000000 0000000 00100110
反码:11111111 11111111 11111111 11011001
补码:11111111 11111111 11111111 11011010
右移两位,左边补充两个0
补码:00 11111111 11111111 11111111 110110
反码:00 11111111 11111111 11111111 110110(因为上个补码符号位是0,为正数,所以对应的反码、原码都一样)
原码:00111111 11111111 11111111 11110110(因为反码符号位是0,为正数,所以原码和反码相同)
最终结果:1073741814
<<< (无此表示符)
不存在 <<< 表示符号。
参考文献:JAVA中 ^、&、|和位运算符的含义详解 (这个文章不错,大家可以参考)