AI悦创

V1

2022/11/11阅读:16主题:凝夜紫

09-Java 中位运算符

你好,我是悦创。

原文首发:https://bornforthis.cn

你好,我是悦创。本次课,先学:https://bornforthis.cn/posts/21.html

0. 目录

  • 字面值的八进制和十六进制
  • 按位运算符
  • 位移运算符
  • 位运算符不会改变原变量的值
  • 位运算符用处

1. 字面值的八进制和十六进制

1.1 以 0 开头的整数为八进制

  • 05 就是十进制的 5
  • 011就是十进制的 9

1.2 以 0x 开头的整数位十六进制

  • 0、1、2、3、4、5、6、7、8、9、A、B、C、D、E、F;
  • 0xF 就是十进制的 15
  • 0x11 就是十进制的 17
public class LiteralNumber {
    public static void main(String[] args) {
        int a = 05;
        int b = 011;
        int c = 0xF;
        int d = 0x11;  // x、X 都可以

        System.out.println(a);  // 5
        System.out.println(b);  // 9
        System.out.println(c);  // 15
        System.out.println(d);  // 17
    }
}

2. 按位运算符【每个二进制的位】

  • 按位并(AND):&
  • 按位或(OR):|
  • 按位异或(XOR):^【一句话,相异为真 ,运算规则是:两个数转为二进制,然后从高位开始比较,如果相同则为 0,不相同则为 1。】
  • 按位取反:~

储备知识:

  • int 有 4 个字节,每个字节有 8 位,一共 32 位。也就是这样的形式: 00000000 00000000 00000000 00000000;
  • 32 的二进制是:100000 ,把 32 的二进制放入上面储备知识中得出这样的效果:00000000 00000000 00000000 00100000。当然你也可以缩写成这样的效果:00100000。
  • 接下来我们可以进行取反,取反之后为的结果为: 11011111;
  • 操作的维度是 bit
public class BitCalc {
    public static void main(String[] args) {
        // F->15-> 1111
        // 二进制的 1111 1000
        int a = 0xF8;
        // 二进制的 1111 0100
        int b = 0xF4;
        // 二进制的 1111 1111
        int c = 0xFF;
        System.out.println(a & b); // 240
        System.out.println(a | b); // 252
        System.out.println(a ^ b); // 12
        System.out.println(~c); // -256
    }
}

/* 补充:
a 1111 1000
b 1111 0100
& 1111 0000
| 1111 1100
^ 0000 1100
C 255 > 11111111
~ -255
*/

以我的工作经验来看,Java 中按位运算是比较少的。但是,我们要知道有这样一种操作。这样之后遇到,你就不会一脸懵!在这里,我不推荐你在日后的工作中有使用 **位 **运算符的倾向,当你想到,这个问题可以使用位运算符解决的时候,你再想想有没有更好的,更让人容易理解的方法。当然,如果真没有的话就算了。

3. 位移运算符

推荐先看里面部分内容:https://blog.csdn.net/qq_33254766/article/details/108702875 现代计算机是基于二进制的,我们就来看看,计算机语言中针对二进制的位操作。这里的位操作,也叫作位运算,就是直接对内存中的二进制位进行操作。常见的二进制位操作包括向左移位和向右移位的移位操作,以及“或”“与”“异或”的逻辑操作。「上面已经讲过与或非」下面我们来看位移运算符。

3.1 位移运算符

3.1.1 右移

移位的数字(x) >> 移位量(y) 右移运算是将移动的数字的二进制位数按指定移位量向右移动,右边低位溢出 y 位则舍弃。左边的空位一律补 0 或者补符号位,这由不同的机器而定。 若移位的数字不带符号位,则左边空位补入的数全部为 0;若是带符号数,则补入的数全部为原数最左边的符号位(正数 0,负数 1)PS:

  • :符号位不动,其余位右移,符号位后边补 0,又称带符号右移「原本正数,那移动之后依然是正数。反之亦然。」

  • 当负数右移操作时,先对负数的原码求其补码再进行右移操作。

3.1.2 无符号右移

  • :符号位一起右移,左边补 0,又称无符号右移「无符号右移,那带着符号位意味着如果原本是正数,那符号位就是 0。右移之后,左边补 0。那还是正数。如果原本是负数,那无符号右移就会变成正数。」

3.1.3 左移

将移位的数字的二进制位全部左移指定的移位量移位量由右操作数指定,右操作数必须是非负值,其右边空出的位用 0 填补,高位左移溢出则舍弃该高位。

  • <<:左移,右边补 0。左移没有带符号位一说,因为符号位在最左侧。
    • 换一种方法理解:num << 1,左移1位相当于 num 乘以 2 的 1 次方
public class BitShift {
    public static void main(String[] args) {
        // 0x400 to binary 0100 0000 0000
        int a = 0x400;
        System.out.println(a);  // 1024
        System.out.println(a >> 1); // 0100 0000 0000 >> 1 -> 0010 0000 0000 to decimalism 512【1024/2】
        System.out.println(a >> 2); // 0100 0000 0000 >> 2 -> 0001 0000 0000 to decimalism 256【1024/4】

        System.out.println(a << 1); // 0100 0000 0000 << 1 -> 1000 0000 0000 to decimalism 2048【1024*2】
        System.out.println(a << 2); // 0100 0000 0000 << 2 -> 0001 0000 0000 0000 to decimalism 4096【1024*4】

        System.out.println(a >>> 1); // 0100 0000 0000 >> 1 -> 0010 0000 0000 to decimalism 512【1024/2】
        System.out.println(a >>> 2); // 0100 0000 0000 >> 2 -> 0001 0000 0000 to decimalism 256【1024/4】

        int b = -0x400;
        System.out.println(b);  // -1024
        System.out.println(b >> 1);
        /* -1024
         * 原码:1100 0000 0000
         * 反码:1011 1111 1111
         * 补码:1100 0000 0000
         * 右移:1010 0000 0000
         * 10 0000 0000 to decimalism 512 result >> -512
         */

        System.out.println(b >> 2);
        /* 补码:1100 0000 0000
         * 右移2:1001 0000 0000 to decimalism -256*/

        System.out.println(b << 1);
        /* 补码:0000 1100 0000 0000
         * 左移1:0001 1000 0000 0000 to decimalism -2048*/

        System.out.println(b << 2);
        /* 补码:0000 1100 0000 0000
         *  左移2:0011 0000 0000 0000 to decimalism -4096*/

        System.out.println(b >>> 1);  // 了解即可
        System.out.println(b >>> 2);


    }
}

3.2 位运算符不会改变原变量的值

3.2.1 按位运算符不会改变原本的变量的值

3.2.2 位移运算符不会改变原本的变量的值

public class BitOprtNotChangeVariableValue {
    public static void main(String[] args) {
        int a = 0x400;  // 0100 0000 0000 // 1024
        int b = 0xF4;
        int c = 0xFF;

        System.out.println(a >> 2);  // 256
        System.out.println(~a);  // -1025
        /* 原码:0100 0000 0000
        *  反码:0011 1111 1111
        *  补码:0100 0000 0000
        *  取反:1011 1111 1111 逐位取反,包括符位
        *  补码减1:1011 1111 1110
        *  再取反:1100 0000 0001 -> 取反后的二进制是负数 -> -1025
        */


        System.out.println(a | 0x8);
        /* a 原码:  0100 0000 0000
        *  0x8 原码:0000 0000 1000
        *           0100 0000 1000 -> 1032*/


        System.out.println(a);  // 1024
    }
}

3.3 位运算符用处

3.3.1 按位运算符

  • 掩码(MASK)

3.3.2 位移运算符

  • 高效除以 2
public class BitOprtUsage {
    public static void main(String[] args) {
        int base = 1;
        int is_student_mask = base;
        int is_programmer_mask = base << 1// 0001 -> 0010
        int is_driver_mask = base << 2// 0001 -> 0100
        int is_painter_mask = base << 3// 0001 -> 1000

        int data = 5;

        boolean isStudent = (data & is_student_mask) != 0// true
        //System.out.println(data & is_student_mask); // 1
        /*data:             0101
        * is_student_mask:  0001
        *                   0001 -> 1*/

        System.out.println(isStudent);

        boolean isProgrammer = (data & is_programmer_mask) != 0;
        System.out.println(isProgrammer);

        boolean isDriver = (data & is_driver_mask) != 0;
        System.out.println(isDriver);

        boolean isPainter = (data & is_painter_mask) != 0;
        System.out.println(isPainter);
    }
}

AI悦创·编程一对一

AI悦创·推出辅导班啦,包括「Python 语言辅导班、C++ 辅导班、java 辅导班、算法/数据结构辅导班、少儿编程、pygame 游戏开发」,全部都是一对一教学:一对一辅导 + 一对一答疑 + 布置作业 + 项目实践等。当然,还有线下线上摄影课程、Photoshop、Premiere 一对一教学、QQ、微信在线,随时响应!微信:Jiabcdefh

C++ 信息奥赛题解,长期更新!长期招收一对一中小学信息奥赛集训,莆田、厦门地区有机会线下上门,其他地区线上。微信:Jiabcdefh

分类:

后端

标签:

Java

作者介绍

AI悦创
V1

编程一对一教学,微信:Jiabcdefh