JAVA中的位运算和使用举例

Posted 顧棟

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JAVA中的位运算和使用举例相关的知识,希望对你有一定的参考价值。

JAVA中的位运算和使用举例

如果对二进制码的转换不是很熟悉,建议先看原码 反码 补码 移码

位运算是一种直接操作二进制位实现计算的方式,效率较高,在算法上会采用位运算。

JAVA支持的位运算符有

位运算符描述运算规则
<<左移将操作符左边的操作数的二进制位全部左移操作符右边数值的位。
>>右移将操作符左边的操作数的二进制位全部右移操作符右边数值的位,正数高位补0,负数高位补1,低位丢弃
>>>无符号右移将操作符左边的操作数的二进制位全部右移操作符右边数值的位,高位补0,低位丢弃
&位与当运算符两边操作数二进制形式相同位置的值,逢0得0,其他得1
|位或当运算符两边操作数二进制形式相同位置的值,逢1得1,其他得0
^位异或当运算符两边操作数二进制形式相同位置的值,相同得0,不同得1
~位非这个操作比较特别,它只需要一个操作数,将运算符后的二进制数反转,0变1,1变0

不存在<<<

运算演示

  • <<:左移,运算符规则是:各二进位全部左移若干位,高位丢弃,低位补0。

    例如:3 << 2 ,代表将3的二进制表示,左移2位,int型占4个字节,也就是占32位 由右向左

    32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1  | 位的序号
    --------------------------------------------------------------------------------------  | 
     0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 0 0 0 0 0 0 0 1 1  | 3的二进制
                                                                                            |
     0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 0 0 0 0 0 1 1 0 0  | 3 << 2 =12 
    

    左移常被用来做 ∗ ( 2 n ) * (2 ^ n) (2n)的运算,因为直接基于二进制运算,所以左移效率比 ∗ ( 2 n ) * (2 ^ n) (2n)高。以上述例子来讲,左移2位就是 ∗ 2 2 *2^2 22,即 3 ∗ 4 = 12 3*4=12 34=12

  • >>:右移,运算符规则是:各二进位全部右移若干位,正数高位补0,负数高位补1,低位丢弃。

    例如: 13 >> 2 = 3,代表将12的二进制表示,右移2位,int型占4个字节,也就是占32位 由右向左

    32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1  | 位的序号
    --------------------------------------------------------------------------------------  | 
     0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 0 0 0 0 0 1 1 0 1  | 13的二进制
                                                                                            |
     0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 0 0 0 0 0 0 0 1 1  | 13 >> 2 = 3
    

    例如: -13 >> 2 = -3,代表将12的二进制表示,右移2位,int型占4个字节,也就是占32位 由右向左

    32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1  | 位的序号
    --------------------------------------------------------------------------------------  |
     1  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 0 0 0 0 0 1 1 0 1  | -13的二进制 原码
     1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1 1 1 1 1 1 0 0 1 0  | -13的二进制 反码
     1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1 1 1 1 1 1 0 0 1 1  | -13的二进制 补码
                                                                                            |
     1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1 1 1 1 1 1 1 1 0 0  | -13 >> 2  补码
     1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1 1 1 1 1 1 1 0 1 1  | -13 >> 2  反码
     1  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 0 0 0 0 0 0 1 0 0  | -13 >> 2 = -4 原码
    

    如果是非负数和负数且是偶数的数进行右移n位,那么等于 ⌈ / ( 2 n ) ⌉ \\lceil / (2^n) \\rceil /(2n)的运算

    如果是负数且是基数的数进行右移n位,则等于 ⌊ / ( 2 n ) ⌋ \\lfloor / (2^n) \\rfloor /(2n)的运算

    向上取整:比自己大的最小整数;数学符号 ⌈ \\lceil ⌉ \\rceil
    向下取整:比自己小的最大整数;数学符号 ⌊ \\lfloor ⌋ \\rfloor

  • >>>:无符号右移,运算符规则是:各二进制位全部右移若干位,高位补0,低位丢弃。

    例如: 13 >>> 2

    32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1  | 位的序号
    --------------------------------------------------------------------------------------  | 
     0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 0 0 0 0 0 1 1 0 1  | 13的二进制
                                                                                            |
     0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 0 0 0 0 0 0 0 1 1  | 13 >> 2 = 3
    

    例如: -13 >>> 2

    32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1  | 位的序号
    --------------------------------------------------------------------------------------  |
     1  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 0 0 0 0 0 1 1 0 1  | -13的二进制 原码
     1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1 1 1 1 1 1 0 0 1 0  | -13的二进制 反码
     1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1 1 1 1 1 1 0 0 1 1  | -13的二进制 补码
                                                                                            |
     0  0  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1 1 1 1 1 1 1 1 0 0  | -13 >>> 2 = 1073741820  补码(原码) 最高位是0 为正数,补码即原码
    
  • &:位与,运算规则是:当运算符两边相同位置的值,同为1时返回1,其他返回0。

    例如: 13 & 2

    32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1  | 位的序号
    --------------------------------------------------------------------------------------  | 
     0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 0 0 0 0 0 1 1 0 1  | 13的二进制
     0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 0 0 0 0 0 0 0 1 0  | 2的二进制
                                                                                            |
     0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 0 0 0 0 0 0 0 0 0  | 13 & 2 = 0
    

    例如: -13 & 2

    32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1  | 位的序号
    --------------------------------------------------------------------------------------  | 
     1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1 1 1 1 1 1 0 0 1 1  | -13的二进制 补码
     0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 0 0 0 0 0 0 0 1 0  | 2的二进制
                                                                                            |
     0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 0 0 0 0 0 0 0 1 0  | -13 & 2 = 2
    
  • |:位或,运算规则是:当运算符两边相同位置的值,同为0时返回0,其他返回1。

    例如: 13 | 2

    32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1  | 位的序号
    --------------------------------------------------------------------------------------  | 
     0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 0 0 0 0 0 1 1 0 1  | 13的二进制
     0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 0 0 0 0 0 0 0 1 0  | 2的二进制
                                                                                            |
     0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 0 0 0 0 0 1 1 1 1  | 13 | 2 = 15
    
  • ^:位异或,运算规则是:当运算符两边相同位置的值,相同时返回0,不相同时返回1。

    例如: 13 ^ 2

    32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1  | 位的序号
    --------------------------------------------------------------------------------------  | 
     0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 0 0 0 0 0 1 1 0 1  | 13的二进制
     0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 0 0 0 0 0 0 0 1 0  | 2的二进制
                                                                                            |
     0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 0 0 0 0 0 1 1 1 1  | 13 ^ 2 = 15
    

    例如: 18 ^ 2

    32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1  | 位的序号
    --------------------------------------------------------------------------------------  | 
     0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 0 0 0 0 1 0 0 1 0  | 18的二进制
     0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 0 0 0 0 0 0 0 1 0  | 2的二进制
                                                                                            |
     0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 0 0 0 0 1 0 0 0 0  | 18 ^ 2 = 15
    

    例如: -13 ^ 2

    32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1  | 位的序号
    --------------------------------------------------------------------------------------  |
     1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1 1 1 1 1 1 0 0 1 1  | -13的二进制 补码
     0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 0 0 0 0 0 0 0 1 0  | 2的二进制
                                                                                            |
     1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1 1 1 1 1 1 0 0 0 1  | -13 ^ 2 补码
     1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1 1 1 1 1 1 0 0 0 0  | -13 ^ 2 反码
     1  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 0 0 0 0 0 1 1 1 1  | -13 ^ 2 = -15原码
    
  • ~:位非,这个操作比较特别,他只需要一个操作数,将运算符后二进制数反转,0变1,1变0 。

    例如: ~13

    32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1  | 位的序号
    --------------------------------------------------------------------------------------  |
     0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 0 0 0 0 0 1 1 0 1  | 13的二进制
                                                                                            |
     1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1 1 1 1 1 1 0 0 1 0  | ~13的补码
     1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1 1 1 1 1 1 0 0 0 1  | ~13的反码
     1  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 0 0 0 0 0 1 1 1 0  | ~13=-14的原码
    

    例如: ~-13

    32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1  | 位的序号
    --------------------------------------------------------------------------------------  |
     1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1 1 1 1 1 1 0 0 1 1  | -13的二进制 补码
                                                                                            |
     0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 0 0 0 0 0 1 1 0 0  | ~-13=12的补码
    

使用场景

  • 奇偶数

    奇数的二进制的第一位(最低位)是1,那么通过 ( n & 1 ) = = 0 (n \\& 1)==0 (n&1)==0为true则为偶数

  • 数的交换

    交换A与B

    a ^= b;
    b ^= a;
    a ^= b;
    
  • 2 n 2^n 2n的数值进行取模计算

    a % 2 n a \\% 2^n a%2n 等价于 a & ( 2 n − 1 ) a\\&(2^n-1) a&(2n1)

  • 生成第一个大于等于a的满足 2 n 2^n 2n的数

    static final int MAXIMUM_CAPACITY = 1 << 30;
    /**
    * 生成第一个大于等于a的满足2的n次方的数
    */
    static final int tableSizeFor(int cap) 
            // 整体思想是通过移位和或运算,计算出cap二进制中比cap大且与2的n次方的二进制相差1的数。从出现1的最高位,往最低位方向,通过或运算进行位上的0变1的的方式进行计算,int型一共32位,1+2+4+8+16=31,这边一共移动了31位。而 cap - 1是为了处理边界
            int n = cap - 1;
            n |= n >>> 1;
            n |= n >>> 2;
            n |= n >>> 4;
            n |= n >>> 8;
            n |= n >>> 16;
            return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
    
    

    整体思想是通过移位和或运算,计算出cap二进制中比cap大且与2的n次方的二进制相差1的数。从出现1的最高位,往最低位方向,通过或运算进行位上的0变1的的方式进行计算,int型一共32位,1+2+4+8+16=31,这边一共移动了31位。而 cap - 1是为了处理边界。当cap是8的时候,这个方法的应该返回8,但是如果不-1,会返回16。

  • 2 n 2^n 2n的数值进行乘法计算

    a ∗ 2 n a*2^n a2n等价于 a < < n a<<n a<<n

  • 求相反数

    (   a + 1 ) (~a+1) ( a+1)

  • 求绝对值

    a > > 31 = = 0 ? a : (   a + 1 ) a >> 31 == 0 ? a : ( ~ a + 1) a>>31==0?a:( a+1)

以上是关于JAVA中的位运算和使用举例的主要内容,如果未能解决你的问题,请参考以下文章

c语言中怎么将十六进制中的高位和低位分别存到数组中

JAVA中的位运算和使用举例

Java编程思想学习杂记(1-4章)

HashMap位运算你可知一二

计算机组成原理——移位运算

计算机组成原理——移位运算