Java 里面的位运算总结

1,044 阅读8分钟
原文链接: ecit13218.github.io

在进行Java位运算之前,首先需要了解一下在计算机中原码,补码,还有反码的知识。

原码表示法是机器数的一种简单的表示法。

其符号位用0表示正号,用:表示负号,数值一般用二进制形式表示。

机器数的反码可由原码得到。如果机器数是正数,则该机器数的反码与原码一样;
如果机器数是负数,则该机器数的反码是对它的原码(符号位除外)各位取反而得到的。

机器数的补码可由原码得到。如果机器数是正数,则该机器数的补码与原码一样;

如果机器数是负数,则该机器数的补码是对它的原码(除符号位外)各位取反,并在未位加1而得到的。

因为在电脑中存储数值都是用补码来进行存储的,所以对负数的计算首先要先算出它的补码值

下面对java的一些位运算符进行实例计算
首先是运算符分为 & | ~ ^ >> << >>>
意义分别为 位与’&’,位或’|’,位非’~’,位异或’^’,右移’>>’,左移’<<’,0填充的右移’>>>’
其中位与运算是二者为1时才为1,否则为0
位或运算为两者有一个为1时则为1,否则为0
位非运算,0转换成1,1转换成0,首先高位符号位从0转为1
异或运算为两者都相同时则为0,否则为1

int a=129;//10000001
int b=128;//10000000
System.out.println("位与运算"+(a&b));//位与运算时两者为1时才为1,否则为0 结果为 1000 0000=128
System.out.println("位或运算"+(a|b));//位或运算为两者有一个为1时则为1,否则为0,结果为 1000 0001=129
System.out.println("位非运算"+(~b));//位非运算,0转换成1,1转换成0,首先高位符号位从0转为1
//结果为1111 1111 1111 1111 1111 1111 1111 0111 1111 对这个数进行取反
//结果为1000 0000 0000 0000 0000 0000 0000 1000 0000
// 加1后结果 1000 0000 0000 0000 0000 0000 0000 1000 0001
//答案为-129
System.out.println("异或运算"+(a^b));//异或运算为两者都相同时则为0,否则为1 结果为 00000001=1
运行结果为: 位与运算=128
位或运算=129
位非运算=-129
异或运算=1

下面对符号左移,符号右移,无符号右移进行描述(java中没有无符号左移)
负数右移时左边补1,正数右移时左边补0,无符号右移时无论是正数还是负数均左边补0。
int c=128;//1000 0000
int d=4;
System.out.println("符号右移="+(c>>d));
//右移四位相当于除以2的4次方,相当于128/16=8,实际上为1000 0000
//               0000 0000 0000 0000 0000 0000 1000 0000
//右移四位结果为  0000 0000 0000 0000 0000 0000 0000 1000  结果为8
System.out.println("符号左移="+(c<<d));
//左移四位相当于乘上2的4次方,相当于128*16=2048
//              0000 0000 0000 0000 0000 0000 1000 0000
//左移四位结果为 0000 0000 0000 0000 0000 1000 0000 0000=2的11次方=2048
System.out.println("无符号右移="+(c>>>d));
//右移四位相当于除以2的4次方,相当于128/16=8,实际上为1000 0000
//               0000 0000 0000 0000 0000 0000 1000 0000
//右移四位结果为  0000 0000 0000 0000 0000 0000 0000 1000  结果为8

得到结果为

符号右移=8

符号左移=2048

无符号右移=8


下面对负数进行右移左移及无符号右移进行计算

int m=-128;
int n=4;
System.out.println("符号右移="+(m>>n));
// 1000 0000 0000 0000 0000 0000 1000 0000  -128的原码
// 1111 1111 1111 1111 1111 1111 0111 1111  -128的反码
// 1111 1111 1111 1111 1111 1111 1000 0000  -128的补码
// 1111 1111 1111 1111 1111 1111 1111 1000  负数右移时左边补1,正数右移时左边补0,这里重新取补码得到答案
// 1000 0000 0000 0000 0000 0000 0000 0111  取反得
// 1000 0000 0000 0000 0000 0000 0000 1000  取补得结果为-8
System.out.println("符号左移="+(m<<n));
// 1111 1111 1111 1111 1111 1111 1000 0000  -128的补码
// 1111 1111 1111 1111 1111 1000 0000 0000  左移时右边补0,符号位不变
// 1000 0000 0000 0000 0000 0111 1111 1111  取反时符号位不变
// 1000 0000 0000 0000 0000 1000 0000 0000  取补码为 -2048
System.out.println("无符号右移="+(m>>>n));
//无符号右移时左侧只补0
//1111 1111 1111 1111 1111 1111 1000 0000  -128的补码
//0000 1111 1111 1111 1111 1111 1111 1000  直接得出答案

符号右移=-8

符号左移=-2048

无符号右移=268435448

这里要重新重点强调一下,正数的 原码,反码和补码全部相同。所以算出答案后直接转换成正数值


假如右移的是负数位的情况也有
在java中对int型的右移则是让这个负数位和0b11111进行位与运算,对long类型的则是和0b111111进行位与运算
这里参考于:Chapter 15. Expressions

If the promoted type of the left-hand operand is int, then only the five lowest-order bits of the right-hand operand are used as the shift distance. It is as if the right-hand operand were subjected to a bitwise logical AND operator& (§15.22.1) with the mask value 0x1f (0b11111). The shift distance actually used is therefore always in the range 0 to 31, inclusive.
If the promoted type of the left-hand operand is long, then only the six lowest-order bits of the right-hand operand are used as the shift distance. It is as if the right-hand operand were subjected to a bitwise logical AND operator & (§15.22.1) with the mask value 0x3f (0b111111). The shift distance actually used is therefore always in the range 0 to 63, inclusive.



int k=2048;
int l=-30;
System.out.println(k>>l);

//位移负数位
//题目效果为 2048>>(-30&0b11111)
//-30的原码为1000 0000 0000 0000 0000 0000 0001 1110
//-30的反码为1111 1111 1111 1111 1111 1111 1110 0001
//-30的补码为1111 1111 1111 1111 1111 1111 1110 0010
// 0000 0000 0000 0000 0000 0000 0001 1111 int型取后5位,long型后6位均为1
// 0000 0000 0000 0000 0000 0000 0000 0010 进行位与运算后得到结果为2
//上面相当于效果为2048 右移两位 得到答案为 512

最终结果得到为512

Older Hello World