按位逻辑操作符那些事儿

title: 按位逻辑操作符那些事儿

date: 2017-02-24

tag: java


按位操作符运算符概述

在java底层里面,用到了很多这种符号,不对这些按位逻辑符号弄清楚,不容易看懂jdk源码,这里对按位符号做一个简单的梳理

运算符用法描述
按位与( AND)a & b对于每一个比特位,只有两个操作数相应的比特位都是1时,结果才为1,否则为0。
按位或(OR)a | b对于每一个比特位,当两个操作数相应的比特位至少有一个1时,结果为1,否则为0。
按位异或(XOR)a ^ b对于每一个比特位,当两个操作数相应的比特位有且只有一个1时,结果为1,否则为0。
按位非(NOT)~ a反转操作数的比特位,即0变成1,1变成0。
左移(L)a << ba 的二进制形式向左移 b (< 32) 比特位,右边用0填充。
有符号右移a >> b将 a 的二进制表示向右移b(< 32) 位,丢弃被移出的位。
无符号右移a >>> b将 a 的二进制表示向右移b(< 32) 位,丢弃被移出的位,并使用 0 在左侧填充。

这里注意,java里面没有无符号左移,因为无符号左移<<<和左移<<是一样的概念

按位逻辑操作符

& (按位与)

对每对比特位执行与(AND)操作。只有 a 和 b 都是 1 时,a AND b 才是 1。与操作的真值表如下:

aba AND b
000
010
100
111

上代码:

@Test
public void testAnweiyu(){
    //按位与,1与0位0,1与1为1,0与0为0
    int a=14 & 8;
    toBinaryOutPut(14,"&",8);
    System.out.println(Integer.toBinaryString(a)+"===="+a);
}
结果:
1110 & 1000
1000====8

| (按位或)

对每一对比特位执行或(OR)操作。如果 a 或 b 为 1,则 a OR b 结果为 1。或操作的真值表:

aba OR b
000
011
101
111
@Test
public void testAnweiHuo(){
    //按位或,1或0为1,0或0为0,1或1为1
    int a=14 | 8;
    toBinaryOutPut(14,"|",8);
    System.out.println(Integer.toBinaryString(a)+"===="+a);
}
结果
1110 | 1000
1110====14

^ (按位异或)

对每一对比特位执行异或(XOR)操作。当 a 和 b 不相同时,a XOR b 的结果为 1。异或操作真值表:

aba XOR b
000
011
101
110
 @Test
    public void testAnweiYiHuo(){
        int a=14 ^ 8;
        toBinaryOutPut(14,"^",8);
        System.out.println(Integer.toBinaryString(a)+"===="+a);
    }
结果
1110 ^ 1000
110====6

~ (按位非)

对每一个比特位执行非(NOT)操作。NOT a 结果为 a 的反转(即反码)。非操作的真值表:

aNOT a
01
10
@Test
public void testAnweiFei(){
    int a=~14;
    System.out.println(Integer.toBinaryString(14));
    System.out.println(Integer.toBinaryString(a)+"===="+a);
}
结果
1110
11111111111111111111111111110001====-15

按位移动操作符

<<有符号左移

该操作符会将第一个操作数向左移动指定的位数。向左被移出的位被丢弃,右侧用 0 补充

在数字 x 上左移 y 比特得到 x * 2y

上代码

@Test
public void testLeftMove(){
    int a=9<<2;//9左移动2位
    toBinaryOutPut(9,"<<",2);
    System.out.println(Integer.toBinaryString(a)+"===="+a);
}
结果:
1001 << 10
100100====36

>>有符号右移

该操作符会将第一个操作数向右移动指定的位数。向右被移出的位被丢弃,拷贝最左侧的位以填充左侧。由于新的最左侧的位总是和以前相同,符号位没有被改变。所以被称作“符号传播”。

例如, 9 >> 2 得到 2

@Test
public void testRightMove(){
    int a=9>>2;//9右边移动2位
    toBinaryOutPut(9,">>",2);
    System.out.println(Integer.toBinaryString(a)+"===="+a);
}
结果:
1001 >> 10
10====2

>>>无符号右移

该操作符会将第一个操作数向右移动指定的位数。向右被移出的位被丢弃,左侧用0填充。因为符号位变成了 0,所以结果总是非负的。(译注:即便右移 0 个比特,结果也是非负的。)

对于非负数,有符号右移和无符号右移总是返回相同的结果。例如, 9 >>> 2 得到 2 和 9 >> 2相同

但是对于负数却不尽相同。 -9 >>> 2 产生 1073741821 这和 -9 >> 2 不同:

上代码:

@Test
public void testNoSignRightMove(){
    int a=-9>>>2;//9无符号右移动2位
    toBinaryOutPut(-9,">>>",2);
    System.out.println(Integer.toBinaryString(a)+"===="+a);
}
结果:
11111111111111111111111111110111 >>> 10
111111111111111111111111111101====1073741821

提问时间如下:

  • 首先负数的二进制为什么是这样的?

    在计算机中,负数以其正值的补码形式表达,将二进制数按位取反,所得的新二进制数称为原二进制数的反码,然后反码+1就是补码了

    例如:9的原码是00000000 00000000 00000000 00001001

    ​ 反码是11111111 11111111 11111111 11110110

    ​ 补码是11111111 11111111 11111111 11110111

    所以-9是这样的

  • int在计算机中存储的是4字节,所以有32位,所以这么长,前面正数是因为把前面的0省略了

  • 那么有符号右移和无符号右移有什么区别呢?

    一个是copy最左侧的位来填充,一个是用0来填充,所以无符号右移总是一个正数

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值