一、背景知识
整数在内存中是以二进制的形式存在的,而且存的是该整数的补码。最高位代表符号位,正数为0,负数为1
正数的补码是其二进制本身,负数的补码则是 符号位保持1不变,其他位按位取反再加1,+0和-0的补码相同,都是0。
负数在进行按位与运算时是以补码形式参与运算。(这个很好理解,因为负数在内存中本身就是以补码存储的)
二、移位运算
下面介绍三种移位运算,
首先我们对5作运算。
5在内存中的存储形式为:0000 0000 0000 0000 0000 0000 0000 0101
1、左移<<
符号位会被保留,数值位左移一位,低位补0,变为:
0000 0000 0000 0000 0000 0000 0000 1010
得到值为10
2、右移>>
符号位会被保留,数值位左移一位,数值位高位补0,变为:
0000 0000 0000 0000 0000 0000 0000 0010
得到值为2
可以看到,左移相当于乘以2,右移相当于除以2,JDK中很多源码都采用了这种写法,效率高而且优雅
3、无符号右移>>>
>>>在右移时会将符号位当做数值位处理,一起右移,高位补0
为了清楚地演示出符号位的变化,以-5为例:
-5在内存中的存储形式为:1111 1111 1111 1111 1111 1111 1111 1011
>>>1 后得到: 0111 1111 1111 1111 1111 1111 1111 1101
值为2147483645,很明显,无论从10进制数值,还是从内存中的存储,都能看出,该值比Integer的最大值小2
代码如下:
/** * @Description: * @projectName:JavaTest * @see:PACKAGE_NAME * @author:郑晓龙 * @createTime:2019/5/15 23:30 * @version:1.0 */ public class ShiftOperationTest { public static void main(String[] args) { System.out.println(5<<1); System.out.println(5>>1); System.out.println(-5>>>1); System.out.println(Integer.MAX_VALUE); } }
运行结果:
10 2 2147483645 2147483647
最后,强迫症来了,为什么没有<<<
我认为是这样的:内存中是将整数以二进制的补码形式存放,最高位是符号位,左移时最高位有可能是1或0,符号位不能确定,也就无法满足无符号左移的定义,而右移可以规定高位补0,即可以确保符号位为0。