Java中的位运算
Java提供了多种位运算,包括 左移( << )、右移( >> ) 、无符号右移( >>> ) 、位与( & ) 、位或( | )、位非( ~ )、位异或( ^ ),除了 ~ 为一元操作符,其他都为二元操作符。
左移和右移
什么是左右移操作,产生的结果是什么
使用 符号 <<
对数字产生的影响就是左移,同理右移。下面通过例子来看左移(右移)的结果:
在 ArrayList
中,使用了grow()
方法进行List的扩容操作,其实,在grow()
方法内部就使用到了右移操作。
1 | private void grow(int minCapacity) { |
grow() 函数的作用就是对 List 进行倍数的扩容,这个倍数就是 x + x >> 1
,具体产生的结果用主函数进行测试。
1 | System.out.println(10+(10>>1)); |
产生的结果为15.也就是说 10>>1
的结果为5.那么计算过程是什么样的呢,才会产生这样的结果?
转化为二进制
对位的运算,第一步一定是先转化为二进制,再对二进制进行计算。
例子中的 10 转化为二进制为:
0000 0000 0000 0000 0000 0000 0000 1010
进行为运算
如果是左移,则在右侧补0,同理如果是右移,则在左侧补0。
比如上面的 10>>1 , 右移一位,则在左侧补一个0。
结果为 ...... 0101
结果为 5
如果 10<<1 ,左移一位,则在右侧补一个0
结果为 ......1 0100
结果为 20
无符号左移右移
负数以原码的补码形式表达,如果是负数时,比如 -10 ,转化为二进制就是
1111 1111 1111 1111 1111 1111 1111 1011
也就是高位为1,与正数相反,同理,在进行移动时,也需要将原来的补0,调整为补1;
如 -10>>1,右移一位,左侧补1
1......1101
,结果为 -5
无符号则始终补0;
综上:
- 转化为二进制
- 正数反向补0
- 负数反向补1
- 无符号反向补0
位与(&)
在HashMap中进行put元素的时候,会通过 putVal()
方法进行实际的计算和添加。
1 | final V putVal(int hash, K key, V value, boolean onlyIfAbsent, |
这里使用 & 的作用其实是为了保证 hash 的值不超过范围。数组具有2的幂数长度,以用&替换昂贵的取模运算。
运算规则:第一个数的的第n位和第二个数的第n位如果都是1,那么结果的第n为也为1,否则为0 简化描述规则:同一为一,否则为零
5转换为二进制:0000 0000 0000 0000 0000 0000 0000 0101
3转换为二进制:0000 0000 0000 0000 0000 0000 0000 0011
结果:0000 0000 0000 0000 0000 0000 0000 0001
转化为10进制为 1
可以作用为关闭(屏蔽)特定位的手段
位或(|)
运算规则:第一个数的的第n位于第二个数的第n位 只要有一个是1,那么结果的第n为也为1,否则为0. 简化规则描述: 有一则一,否则为零
5转换为二进制:0000 0000 0000 0000 0000 0000 0000 0101
3转换为二进制:0000 0000 0000 0000 0000 0000 0000 0011
结果:0000 0000 0000 0000 0000 0000 0000 0110
转化为10进制为 7
可以作为将特定位置为1的手段
异或(^)
运算规则:第一个数的的第n位于第二个数的第n位 相反,那么结果的第n为也为1,否则为0,简化规则描述: 相反为一,否则为零
5转换为二进制:0000 0000 0000 0000 0000 0000 0000 0101
3转换为二进制:0000 0000 0000 0000 0000 0000 0000 0011
结果:0000 0000 0000 0000 0000 0000 0000 0110
转化为二进制为 7
- 按位“异或”运算可以使特定的位取反
- 直接交换两个变量的值
1 | a^=b |
这样a的值与b的值就形成了互换。