背景
java或android源码中经常会使用移位运算来代替乘除运算,因为移位运算的性能比乘除运算的高(PS:对于计算机而言,移位运算只是移了个位置),所以了解移位运算的计算过程对于我们阅读源码会有一定的帮助。
原码、反码、补码
原码是人脑最容易理解和计算的表示方式
第一位表示符号, 其余位表示值
-1的原码是10000000 00000000 00000000 00000001
反码是人脑无法直观看出其数值的. 通常需要转换成原码在计算其数值
正数的反码是其本身
负数的反码是在其原码的基础上, 符号位不变,其余各个位取反
-1的反码是11111111 11111111 11111111 11111110
补码是人脑无法直观看出其数值的. 通常需要转换成原码在计算其数值
正数的补码就是其本身
负数的补码是在其原码的基础上, 符号位不变, 其余各位取反, 最后+1. (即在反码的基础上+1)
-1的补码是11111111 11111111 11111111 11111111
左移运算符:<<
System.out.println(1<<1); // 2
System.out.println(1<<32); // 1
System.out.println(-1<<1); // -2
System.out.println(-1<<32); // -1
结论:丢弃左边指定位数,右边补0
右移运算符:>>
System.out.println(1>>1); // 0
System.out.println(1>>32); // 1
System.out.println(-1>>1); // -1,因为-1的二进制反码是11111111 11111111 11111111 11111111
System.out.println(-1>>32); // -1
结论:丢弃右边指定位数,左边补上符号位
无符号右移运算符:>>>
System.out.println(1>>>1); // 0
System.out.println(1>>>32); // 1
System.out.println(-1>>>1); // 2147483647
System.out.println(-1>>>32); // -1,这里仍然是-1,是因为int类型是32位,32%32=0,所以实际上并没有发生移位
结论:丢弃右边指定位数,左边补上0
结论
对于机器而言,java中的移位运算都是对补码
执行移位运算的,下面以-1<<1=-2为例进行讲解:
- -1的原码:10000000 00000000 00000000 00000001
- -1的反码:11111111 11111111 11111111 11111110
- -1的补码:11111111 11111111 11111111 11111111
- 执行移位操作
- -1移位后的补码:11111111 11111111 11111111 11111110
- -1移位后的反码:11111111 11111111 11111111 11111101
- -1移位后的原码:10000000 00000000 00000000 00000010
- 得到最后的原码十进制值为-2