• Java - 位运算的基本原理和用途


    前言

    Java 当中的位运算有很多种,它们都是针对二进制位进行操作。包括:

    • 按位与:&
    • 按位或: |
    • 按位异或: ^
    • 取反:~
    • 左移位、右移位运算符:<< ,>> ,>>>

    接下来我们就复习一下相关的运算知识。

    一. Java 位运算基本操作

    1.1 按位与 &

    按位与:两个二进制数对应位上的数字都为1时,结果位上的数字才为1。否则结果位上的数字为0。按位与通常用于掩码操作或清零操作。

    举例如下:

    3的二进制表示为:0 0 1 1
    5的二进制表示为:0 1 0 1
    那么3 & 5 则表示为:
    0 & 0 = 0
    0 & 1 = 0
    1 & 0 = 0
    1 & 1 = 1
    最终结果为:
    0011 & 0101 = 0001 = 1

    按位与 常见的运用有:

    • 判断一个数是否为奇数n & 1 ==1 代替 (n % 2 == 1)
    • 清除一个数的二进制末尾 n 位:x & (~0 << n)

    1.2 按位或 |

    按位或:二进制数对应位上的数字有一个为1时,结果位上的数字就为1

    举例如下:

    3的二进制表示为:0 0 1 1
    5的二进制表示为:0 1 0 1
    那么3 | 5 则表示为:
    0 | 0 = 0
    0 | 1 = 1
    1 | 0 = 1
    1 | 1 = 1
    最终结果为:
    0011 | 0101 = 0111 = 7

    按位或 常用的运用有:

    • 将一个数的二进制末n位设置为1:x | ((1 << n) - 1)

    1.3 按位异或 ^

    按位异或:两个二进制数对应位上的数字不相同时,结果位上的数字为1;否则结果位上的数字为0。

    举例如下:

    3的二进制表示为:0 0 1 1
    5的二进制表示为:0 1 0 1
    那么3 ^ 5 则表示为:
    0 ^ 0 = 0
    0 ^ 1 = 1
    1 ^ 0 = 1
    1 ^ 1 = 0
    最终结果为:
    0011 | 0101 = 0110 = 6

    按位异或 常见的运用有:

    • 加解密操作。

    还有常见的运算公式:

    • x ^ 0 = x​
    • x ^ 1 = ~x

    1.4 按位取反 ~

    按位取反:是指一个二进制数的每个位取反,即0变成1,1变成0。说简单点,对于一个二进制数,取反后的值也就是数值加1后取反数 : ~n = (n+1) * -1

    举例如下:

    3的二进制表示为:0000 0000 0000 0000 0000 0000 0000 0011
    按位取反操作会将每一位取反,即将0变为1,将1变为0。所以,对3进行按位取反的结果为:
    1111 1111 1111 1111 1111 1111 1111 1100
    这个二进制数表示的是一个负数,根据补码的规则,我们需要将其转换为原码来得到对应的十进制数。转换原码的方法是将补码的每一位取反,然后再加1
    对于
    1111 1111 1111 1111 1111 1111 1111 1100
    取反得到
    0000 0000 0000 0000 0000 0000 0000 0011
    再加1得到
    0000 0000 0000 0000 0000 0000 0000 0100,
    即十进制数-4

    1.5 位移运算

    位移运算分为:

    • 左移运算符(<<
    • 右移运算符(>>
    • 无符号右移运算符(>>>

    注意:没有 <<< 这种运算符的哦~

    1.5.1 左移运算符 <<

    左移运算符:将操作数的二进制表示向左移动指定的位数,右侧用0填充。例如,a << b表示将a的二进制表示向左移动b位。

    举例如下:

    3 << 2 = 12
    3 的二进制表示为 0011
    3 << 2 的运算过程如下:
    0011 -> 1100
    因此,3 << 2 = 12

    说白了就是这个数乘以2的几次幂。

    1.5.2 右移运算符 >>

    右移运算符 :将操作数的二进制表示向右移动指定的位数,左侧用符号位(即正负号位)填充。例如,a >> b表示将a的二进制表示向右移动b位。

    举例如下:

    -6 >> 1 = -3
    -6 的二进制表示为
    1111 1111 1111 1111 1111 1111 1111 1010
    -6 >> 1 的运算过程如下:(关注后面的1010 --> 1101),101 整体向右移动了一位,左侧由1填充。
    1111 1111 1111 1111 1111 1111 1111 1101
    因此,-6 >> 1 = -3

    说白了就是这个数除以2的几次幂。 (取整)

    • 如果操作数是负数:右移操作会在左侧用1填充。
    • 如果操作数是正数,右移操作会在左侧用0填充

    1.5.3 无符号右移运算符 >>>

    无符号右移运算符 :将操作数的二进制表示向右移动指定的位数,左侧用0填充。无符号右移运算符不考虑符号位,所以无论操作数是正数还是负数,都会将左侧的位数填充为0。例如,a >>> b表示将a的二进制表示向右移动b位。

    和右移运算符的区别就是:

    • 无论是正数还是负数:右移操作会在左侧都用0填充。

    例如:6 >>> 1 = 6 / 2¹ = 3

    二. 位运算实际运用

    2.1 判断奇偶性(&的运用)

    一个数和1做按位与操作,返回结果是1代表奇数,否则偶数。

    n & 1 == 1
    
    • 1

    2.2 交换两个数的值(^的运用)

    将两个数字异或比较3次即可。

    public static void main(String[] args) {
        int a = 3, b = -7;
        System.out.println("a= " + a + ",b= " + b);
        a ^= b;
        b ^= a;
        a ^= b;
        System.out.println("a= " + a + ",b= " + b);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    结果如下:
    在这里插入图片描述

    2.3 2的幂运算(<< 的运用)

    给定一个数,想要乘以2的几次m幂:例如3 * 2 的六次幂 = 192,可表示为:

    3 << 6
    
    • 1

    2.4 判断一个数是否是2的幂次方(&的运用)

    对于一个正整数 n,如果它是 2 的幂次方,则有 n & (n - 1) == 0

    2.5 加解密操作(^的运用)

    private static final String TOKEN = "as21312b&*@#";
    
    public static String encrypt(String str) {
        char[] chars1 = str.toCharArray();
        char[] chars2 = TOKEN.toCharArray();
        StringBuilder builder = new StringBuilder();
        for (int i = 0; i < chars1.length; i++) {
            builder.append((char) (chars1[i] ^ chars2[i % chars2.length]));
        }
        return builder.toString();
    }
    
    public static String decrypt(String str) {
        return encrypt(str);
    }
    
    public static void main(String[] args) {
        String str = "Hello World";
        // 加密
        String encrypt = encrypt(str);
        System.out.println(encrypt);
        // 解密
        System.out.println(decrypt(encrypt));
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    运行结果如下:
    在这里插入图片描述
    上面是一个简单的案例,你也可以在他的基础上,多加一层判断,比如:

    • 防止二次加密。
    • 没有加密的字符串经过解密后还是原字符串。
  • 相关阅读:
    综合案例_文件上传的原理和综合案例_文件上传案例的客户端
    layui公共类layui-elip的使用
    SQL 数据库简单使用
    LT6211 双通道、可编程电源电流、轨至轨输出、电流反馈放大器
    (附源码)ssm考务管理系统 毕业设计 221504
    NBA球员数据爬虫练习
    seata分布式事务部署,springCloud集成seata。
    【无标题】
    使用UEFI固件引导KVM虚拟机
    SSL证书一次性购买多年期,有什么好处?
  • 原文地址:https://blog.csdn.net/Zong_0915/article/details/134477936