Java位运算(移位、位与、或、异或、非)


JAVA提供的位运算符:左移(<<)、右移(>>)、无符号右移(>>>)、与(&)、或(|)、非(~)、异或(^),除了非是一元操作符,其他都是二元操作符。

左移(<<)

package show.lmm;

/**
 * 左移
 *
 * @author luoyepiao
 * @date 2021-12-19 22:44
 */
public class ShiftLeft {

    public static void main(String[] args) {
        final int a = 1;
        System.out.println(a<<2);
    }
}

输出结果:4
0000 0000 0000 0000 0000 0000 0000 0001 //将变量a转换成二进制形式
0000 0000 0000 0000 0000 0000 0000 0100 //左移2位,低位补0

速记:指数级增长,a左移1位、2位、3位结果:2、4、8

右移(>>)

package show.lmm;

/**
 * 右移
 *
 * @author luoyepiao
 * @since 2021-12-19 22:55:33
 */
public class ShiftRight {

    public static void main(String[] args) {
        final int a = 4;
        System.out.println(a>>2);
    }
}

输出结果:1
0000 0000 0000 0000 0000 0000 0000 0100 //将变量a转换成二进制形式
0000 0000 0000 0000 0000 0000 0000 0001 //右移2位,低位补0

速记:指数级减少(最小值为0,int最多可以右移31),a右移1位、2位、3位结果:2、1、0

无符号右移(>>>)

package show.lmm;

/**
 * 无符号右移
 *
 * @author luoyepiao
 * @since 2021-12-19 23:06:51
 */
public class UnsignedShiftRight {

    public static void main(String[] args) {
        final int a = -2;
        System.out.println(a>>>1);
        System.out.println(a>>>2);
    }
}

输出结果:2147483647、1073741823
1111 1111 1111 1111 1111 1111 1111 1110 //将变量a转换成二进制形式
0111 1111 1111 1111 1111 1111 1111 1111 //右移1位,符号位补0
0011 1111 1111 1111 1111 1111 1111 1111 //右移2位,符号位补0

与(&)

第一个操作数的的第n位于第二个操作数的第n位如果都是1,那么结果的第n位也为1,否则为0

package show.lmm;

/**
 * 位与
 *
 * @author luoyepiao
 * @since 2021-12-20 22:05:15
 */
public class BitAnd {

    public static void main(String[] args) {
        System.out.println(3&1);
        System.out.println(4&1);
    }
}

结果:1、0
0000 0000 0000 0000 0000 0000 0000 0011 //3的二进制表现形式
0000 0000 0000 0000 0000 0000 0000 0001 //1的二进制表现形式
——————————————————————————————
1转换为二进制:
0000 0000 0000 0000 0000 0000 0000 0001

0000 0000 0000 0000 0000 0000 0000 0100 //3的二进制表现形式
0000 0000 0000 0000 0000 0000 0000 0001 //1的二进制表现形式
0转换为二进制:
0000 0000 0000 0000 0000 0000 0000 0000

位与运算的特殊用途:

  1. 清零(将一个单元与0进行位与运算结果为0)
  2. 盘点奇偶数:用if((a&1)==0) 代替if(a%2==0)来判断a是不是偶数

或(|)

运算规则就是,运算符两边有1,结果就为1,只有当两边同时为0时,结果才为0
例:
0|0=0
0|1=1
1|0=1
1|1=1

例如:2|4

0000 0000 0000 0000 0000 0000 0000 0010     -> 2
0000 0000 0000 0000 0000 0000 0000 0100     -> 4
0000 0000 0000 0000 0000 0000 0000 0110     -> 2 | 4 = 6

使用场景
下面这个方法是摘自HashMap类,这个算法来修改用户使用构造器传进来的size的,这个算法是使用移位和或结合来实现的,性能上比循环判断要好。

public static final int tableSizeFor(int cap) {
    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;
}

非(~)

运算规则:将二进制数翻转,1变0,0变1,所以对一个数取反偶数次,结果是它本身。
例:

1111 1111 1111 1111 1111 1111 1111 1110 //-2
0000 0000 0000 0000 0000 0000 0000 0001 // ~-2=1

应用场景:

  1. 求相反数:~a+1

异或(^)

运算规则:当运算符两边数字相同位值相同,结果返回0,不相同是返回1
例:

0000 0000 0000 0000 0000 0000 0000 0010     -> 2
0000 0000 0000 0000 0000 0000 0000 0101     -> 5
0000 0000 0000 0000 0000 0000 0000 0111     -> 2 | 5 = 7

通常我们交换两个数会用到临时变量

int a = 1;
int b = 2;
int t;
t = a;
a=b;
b=t;

使用异或运算符

a ^= b;
b ^= a;
a ^= b;

应用场景:不借助临时变量交换两个数


文章作者: Ming Ming Liu
文章链接: https://www.lmm.show/4/
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Ming Ming Liu !
  目录