对于位运算符一直懵懵懂懂,今天又研究一遍感觉恍然大悟,俗话说:好记性不如烂笔头。赶紧记下来以防忘记,哈哈~
对于网上大部分说的什么右移1相当于除以2,左移1相当于乘以2在我们思想中形成了根深蒂固的影响,然而这些解释我并不太认可,我们要了解起本质就不会被这些困扰了。
java位运算符有三种:<< 左移 >>有符号右移 >>> 无符号右移。
在此说明一点,位运算符操作的都是二进制数,运算之前请先将十进制转为二进制
- <<(左移运算)
看下面例子之前,先解释下java中的int类型是4个字节(32bit)的,32位太长我们就用1个字节(8bit)做例子
十进制 | 二进制 | 备注 | << 1 | 转化之后的十进制 | << 2 | 转化之后的十进制 |
---|---|---|---|---|---|---|
3 | 0000 0011(原码) | java采用原码表示(正数) | 0000 0110(原码) | 6 | 0000 1100(原码) | 8 |
-3 | 1111 1101(补码) | java采用补码表示(负数) | 1111 1010(补码) | -6 | 1111 0100(补码) | -8 |
如果上面的数字左移6位和左移8位呢?是不是更有点晕了,我们看例子:
十进制 | 二进制 | 备注 | <<6 | 转化之后 | <<8 | 转化之后 |
---|---|---|---|---|---|---|
3 | 0000 0011(原码) | java采用原码表示(正数) | 1100 0000(-64对应的补码) | 你会发现这个应该是个负数,因为符号位为1(没错,此时这个数是-64) | 0000 0011(没有变化) | 3 |
-3 | 1111 1101(补码) | java采用补码表示(负数) | 0100 0000(64对应的原码) | 你会发现这个应该是个正数,因为符号位为0(没错,此时这个数是64) | 1111 1101(没有变化) | -3 |
java在位移时如果>= 8bit时会取模进行位移,如果你位移8位就是 8 - 8 = 0,如果你位移9位 9-8 = 1就是这样。明白了吗?
再次强调我们例子采用的是1个字节(也就是8位);实际中java的int是32位的,所以,如果进行位移运算应该是32 - 32 = 0 ;33-32 = 1这样算的
2.有符号右移>>
运算规则:符号位不动,其他高位补符号位对应的数,(正数补0,负数补1),表格走起:
十进制 | 二进制 | 备注 | >>1 | 转化之后 | >> 7 | 转化之后 |
---|---|---|---|---|---|---|
3 | 0000 0011(原码) | java采用原码表示(正数) | 0000 0001(1的原码) | 1 | 0000 0000 | 0 |
-3 | 1111 1101(补码) | java采用补码表示(负数) | 1111 1110(-2的补码) | -2 | 1111 1111(-1补码) | -1 |
如果右移>=8时,还是会取模运算,同左移
3.无符号位右移 >>>
运算规则:不管正负数,符号位也右移,高位都补0
十进制 | 二进制 | 备注 | >>>1 | 转化之后 |
---|---|---|---|---|
3 | 0000 0011(原码) | java采用原码表示(正数) | 0000 0001 | 1 |
-3 | 1111 1101(补码) | java采用补码表示(负数) | 0111 1110 | 转化之后变成正数了,就是因为符号位移动,高位补0造成的 |