1、关于右移和左移需要注意的地方:
由于类型数值有位数限制,例如java中long型限制8个字节,总共8*8=64位,int型限制4个字节,总共4*8=32位,long和int都有一位是符号位,Java不允许一次性移位左操作数的所有位,对于int型来说也就是右操作数不能大于等于32。右操作数的低5位,5位二进制所代表的最大值为2^5-1,为31,所以取右操作数的低5位,就是只看右操作数的二进制的低5位,相当于右操作数对32取模的结果!相同的道理,long型就是右操作数的低6位有效。
示例(右移):
int a = 1;
a>>=1;//这里1为右操作数,二进制表示为00000000 00000000 00000000 00000001,它的低5位为红色部分,对32取模为1(其实就是和00000000 00000000 00000000 00011111进行&操作)
int a = 1;
a>>=33;//这里1为右操作数,二进制表示为00000000 00000000 00000000 00100001,它的低5位为红色部分,对32取模为1(其实就是和00000000 00000000 00000000 00011111进行&操作)
所以a>>=1和a>>=33的结果是相等的,都为0。
上面是右移的示例,左移的示例也是如此,这里不再赘述,左移结果都为2。
long类型和int类型一样,只不过右操作数取低6位,也就是和
00000000 00000000 00000000 00111111进行&操作
最终的目的就是要保证一次性移动位数不能超过左操作数类型的总位数
2、为什么byte、char、short类型的数移位结果很多时候不如预期?
举一个例子,代码如下:
short i = 1;
i<<=10;
System.out.println(i);
i = 1;
i <<= 16;
System.out.println(i);
结果是
1024
0
按照java的规定byte、char、short移位运算先把类型转换成int型,再进行移位,且结果为int型。
也就是这里面会先将i转换成int类型,所以相应的逻辑应该符合1,这样的话两个结果应该是1024和65536,但为什么是1024和0呢?
这里需要注意,由于short类型是两个字节,所以在赋值给i的时候会进行截断,拿1024来说:
1的二进制为
00000000 00000000 00000000 00000001
左移10位后变成
00000000 00000000 01000000 00000000
转换成short
01000000 00000000
结果为1024
左移16位后变成
00000000 00000001 00000000 00000000
转换成short
00000000 00000000
结果为0
3、为什么0b11111111111111111111111111111111二进制表示的值是-1?
具体的代码如下:
int d = 0b11111111111111111111111111111111;//补码
System.out.println(d);
运行结果是-1
这种情况下,计算机会把二进制值作为补码,那么原码就为0b10000000000000000000000000000001,也就是-1
4、
long a = -1;
a >>>=61;
System.out.println(a);
a = -1;
a >>>=-3;
System.out.println(a);
a = -1;
a >>>=-67;
System.out.println(a);
这里值都为7
需要遵守的规则如下:
1、移动的位数为负数a和移动的位数为'该类型位数'+a效果相同
2、>>>属于无符号的移动,也就是说不管是负数还是正数,符号位用0来补充
3、移动位数超过该类型的最大位数,最终的移动位数对类型位数取模
关于第一个,a>>>=61,由于是无符号右移,所以最终为正数7
关于第二个,a>>>=-3,符合第1条,long型位数为64,向右移动-3就是64+(-3)=61,所以也为7
关于第三个,a>>>=-67,符合第3条,先取模对64取模,为-3,所以也为7