• Java的运算符--与(&)、非(~)、或(|)、异或(^)详解


     一、计算机中存储的都是补码

    java也是如此:

    System.out.println(Integer.toBinaryString(2));
    System.out.println(Integer.toBinaryString(-2));

    运行结果:

    10
    11111111111111111111111111111110

    由于整数默认int型,32位。正数的补码和原码都一样,高位的0默认不打印。因此是10。
    -2

    原码:1000 0000 0000 0000 0000 0000 0000 0010
    反码:1111 1111 1111 1111 1111 1111 1111 1101 (在源码基础上符号位不变,其余位取反)
    补码:1111 1111 1111 1111 1111 1111 1111 1110 (反码+1)
    从上面的结论来看,java二进制数据是以补码来存储的。

    二、运算也是在反码的基础上进行运算的

    1. ~ 按位非(NOT)操作。每位取反。即原来是0的变成1,原来是1的变成0。

    System.out.println(~ (-2)); //结果为1

    分析:

    step1 -> -2原码:1000 0000 0000 0000 0000 0000 0000 0010
    step2 -> -2反码:1111 1111 1111 1111 1111 1111 1111 1101
    step3 -> -2补码:1111 1111 1111 1111 1111 1111 1111 1110
    step4 -> 对-2的补码进行取反即可得到~(-2)的补码
    step5 -> ~(-2)补码:0000 0000 0000 0000 0000 0000 0000 0001
    step6 -> 由于符号位为0表示正数,因此补码和源码一样。转换为十进制就是1

    2. & 按位与(AND)操作。1和1为1,1和0为0,0和0为0。

    System.out.println(-3 & 2); //结果为0

    分析:

    step1 -> -3的原码:1000 0000 0000 0000 0000 0000 0000 0011
    step2 -> -3的反码:1111 1111 1111 1111 1111 1111 1111 1100
    step3 -> -3的补码:1111 1111 1111 1111 1111 1111 1111 1101
    step4 -> 2的补码:0000 0000 0000 0000 0000 0000 0000 0010
    step5 -> step3和step4进行与运算即可得-3&2的补码,结果是正数,补码和原码相同。
    step6 -> -3&2补码: 0000 0000 0000 0000 0000 0000 0000 0000
    step7 -> 转换为十进制就为0

    3. | 按位或(OR)操作。1和1为1,1和0为1,0和0为0。

    System.out.println(-3 | 2); //结果为-1

    分析:

    step1 -> -3的补码:1111 1111 1111 1111 1111 1111 1111 1101
    step2 -> 2的补码:0000 0000 0000 0000 0000 0000 0000 0010
    step3 -> step1和step2进行或运算即可得到-3|2的补码
    step4 -> -3|2补码: 1111 1111 1111 1111 1111 1111 1111 1111
    step5 -> 由于结果是在补码的基础上运算得来个,最高位为1表示负数,负数的补码和原码不相同,因此需要将补码转换为原码。
    step6 -> -3|2反码: 1111 1111 1111 1111 1111 1111 1111 1110(反码到补码是反码+1,因此补码到反码是补码-1)
    step7 -> -3|2原码: 1000 0000 0000 0000 0000 0000 0000 0001(符号位不变,反码取反)
    step7 -> 将step7的二进制转换为十进制,即为-1

    4. ^ 按位异或(XOR)操作。不同为1,相同为0。1和1为0,1和0为1,0和0为0。

    System.out.println(-3 ^ 2); //结果为-1

    分析:

    step1 -> -3的补码:1111 1111 1111 1111 1111 1111 1111 1101
    step2 ->  2的补码:0000 0000 0000 0000 0000 0000 0000 0010
    step3 ->  step1和step2做异或运算得到补码
    step4 -> -3^2补码: 1111 1111 1111 1111 1111 1111 1111 1111
    step5 -> 由于结果是负数,因此需要将运算得补码转换为原码。
    step6 -> -3^2反码: 1111 1111 1111 1111 1111 1111 1111 1110(补码-1)
    step7 -> -3^2原码: 1000 0000 0000 0000 0000 0000 0001 0001(符号位不变,反码取反)
    step8 -> 将step7的二进制原码转换为十进制数,结果为-1

    5. >> 右移位操作(var >> bit)。指定值所有位向右移动指定位数。低位舍弃,高位按符号位填充。没有溢出的情况下,相当于除以2的n次方。

    System.out.println(-3 >> 3); //结果为-1

    分析:

    step1 -> -3的补码:1111 1111 1111 1111 1111 1111 1111 1101
    step2 ->  右移3位
    step3 ->  右移后补码:1111 1111 1111 1111 1111 1111 1111 1111
    step4 -> 高位为负数因此,高位补1,低位舍弃。负数要转换为原码
    step5 ->  右移后反码:1111 1111 1111 1111 1111 1111 1111 1110(补码-1)
    step6 -> 右移后原码:1000 0000 0000 0000 0000 0000 0000 0001(符号位不变,反码取反)
    step7 -> step6转换为十进制值为-1

    6. >>> 无符号右移位操作(var >>> bit)。指定值所有位向右移动指定位数。低位舍弃,高位补0。

    System.out.println(-3 >>> 3); //结果为536870911

    分析:

    step1 -> -3的补码:1111 1111 1111 1111 1111 1111 1111 1101
    step2 -> 无符号右移3位,高位补0,低位舍弃。
    step3 -> 右移后补码:0001 1111 1111 1111 1111 1111 1111 1111
    step4 -> 正数的补码和原码一样。结果为536870911

    7. << 左移位操作(var << bit)。指定值所有位向左移动指定位数。低位补0,高位保留符号位。没有溢出的情况下,相当于乘以2的n次方。

    System.out.println(-3 << 3); //结果为-24

    分析:

    step1 -> -3的补码:1111 1111 1111 1111 1111 1111 1111 1101
    step2 -> 左移3位,高位不变。低位补0
    step3 -> 右移后补码:1111 1111 1111 1111 1111 1111 1110 1000
    step4 -> 右移后反码:1111 1111 1111 1111 1111 1111 1110 0111
    step5 -> 右移后原码:1000 0000 0000 0000 0000 0000 0001 1000
    step6 -> 将step5转换为十进制即为-24
  • 相关阅读:
    shapely and geos break在distance方法
    linux运维
    【未完待补充】linux 设置So动态库链接路径
    用python建立最简单的web服务器
    nginx + keepalived 双机热备
    nagios监控linux主机监控内存脚本
    linux普通用户权限设置为超级用户权限方法、sudo不用登陆密码
    zato server启动后自动关闭问题解决
    Linux下几种文件传输命令 sz rz sftp scp
    python风味之大杂烩
  • 原文地址:https://www.cnblogs.com/wangmingshun/p/5398712.html
Copyright © 2020-2023  润新知