java中的移位操作符
最近在看移位操作符的时候遇到了一个有趣的问题:
- -1无符号右移32位时,会再次变成-1而不是我预期中的0.
首先介绍一下java中的移位操作符: <<(有符号左移操作符) >>(有符号右移操作符) 和>>>(无符号右移操作符)
(负数在java中是以补码的形式存储的:
-1的原码为:
1000 0000 0000 0000 0000 0000 0000 0001
-1的反码为:
1111 1111 1111 1111 1111 1111 1111 1110
-1的补码为:
1111 1111 1111 1111 1111 1111 1111 1111
所以,在java中-1的二进制码为:1111 1111 1111 1111 1111 1111 1111 1111)
- 左移操作符(<<):将二进制数向左移动一位,低位补0.
int i = 1;
System.out.println(Integer.toBinaryString(i));
i<<=1;
System.out.println(Integer.toBinaryString(i));
int j = -1;
System.out.println(Integer.toBinaryString(j));
j<<=1;
System.out.println(Integer.toBinaryString(j));
结果为:
1 //1
10 //2
11111111111111111111111111111111 //-1
11111111111111111111111111111110 //-2
实际上,向左的移位操作符就是将原本的数字乘2.
- (有符号)右移操作符(>>)是将二进制数向右移动一位,高位补符号的数字
int i = 7;
System.out.println(Integer.toBinaryString(i));
i>>=1;
System.out.println(Integer.toBinaryString(i));
int j = -7;
System.out.println(Integer.toBinaryString(j));
j>>=1;
System.out.println(Integer.toBinaryString(j));
结果为:
111//7
11 //3
11111111111111111111111111111001 //-7
11111111111111111111111111111100 //-4
实际上我们看到有符号的右移操作符就是将数字除以二取商,即取模运算.
3.(无符号)右移操作符(>>>)将二进制数向右移动一位,高位补0.
int i = 7;
System.out.println(Integer.toBinaryString(i));
i>>>=1;
System.out.println(Integer.toBinaryString(i));
int j = -7;
System.out.println(Integer.toBinaryString(j));
j>>>=1;
System.out.println(Integer.toBinaryString(j));
111 //7
11 //3
11111111111111111111111111111001 //-7
1111111111111111111111111111100 //2147483644
下面说明遇到的问题:
如上面所说,-1在java中的二进制码为:1111 1111 1111 1111 1111 1111 1111 1111
当我进行无符号的右移操作时,若右移了32位以上,根据高位补0,结果应该变为0.
但是实际上我对-1进行右移时,大于32时不为0.
在网上查资料以后发现,在对int类型的数据进行移位操作时,对于移位数,java中只截取了二进制数的后五位,而对long类型的进行移位时截取后六位.
即最大值为 1 1111 = 31,所以,在进行移位操作时,最大的移位数为31.下面进行实验:
int i = -1;
System.out.println(Integer.toBinaryString(i));
i>>>=10;
System.out.println(Integer.toBinaryString(i));
int j = -1;
System.out.println(Integer.toBinaryString(j));
j>>>=32;
System.out.println(Integer.toBinaryString(j));
int k = -1;
System.out.println(Integer.toBinaryString(k));
k>>>=42;
System.out.println(Integer.toBinaryString(k));
结果为:
11111111111111111111111111111111
1111111111111111111111
11111111111111111111111111111111
11111111111111111111111111111111
11111111111111111111111111111111
1111111111111111111111
右移位数 10 32 42的二进制码如下:
1010
100000
101010
我们看到 10 和42 的后五位都为 01010,所以移位后结果一致.
而右移32时后五位为0 0000 和右移0位的后五位一致,所以结果不变
我们再进行一组实验:
int i = -7;
System.out.println(Integer.toBinaryString(i));
i>>>=-22;
System.out.println(Integer.toBinaryString(i));
int j = -7;
System.out.println(Integer.toBinaryString(j));
j>>>=10;
System.out.println(Integer.toBinaryString(j));
11111111111111111111111111111001
1111111111111111111111
11111111111111111111111111111001
1111111111111111111111
在上面的的代码中对-7进行了-22的右移和10的右移,我们发现结果一致.
对比-22 和 10 的二进制数为:
11111111111111111111111111101010
1010
后五位 01010一致,所以右移的结果一致