深入理解Java中的位运算符

2023-11-21 11:29:12 浏览数 (1)


theme: healer-readable

highlight: a11y-dark


哈喽,各位小伙伴们,你们好呀,我是喵手。

  今天我要给大家分享一些自己日常学习到的一些知识点,并以文字的形式跟大家一起交流,互相学习,一个人虽可以走的更快,但一群人可以走的更远。

  我是一名后端开发爱好者,工作日常接触到最多的就是Java语言啦,所以我都尽量抽业余时间把自己所学到所会的,通过文章的形式进行输出,希望以这种方式帮助到更多的初学者或者想入门的小伙伴们,同时也能对自己的技术进行沉淀,加以复盘,查缺补漏。

小伙伴们在批阅的过程中,如果觉得文章不错,欢迎点赞、收藏、关注哦。三连即是对作者我写作道路上最好的鼓励与支持!

前言

  Java是一门广泛使用的编程语言,拥有丰富的运算符来支持代码的实现。位运算符是其中的一类,它们在处理整数类型的数据时十分有用,也是Java开发中经常用到的运算符之一。

摘要

  本文将深入介绍Java中的位运算符,包括按位与、按位或、按位异或、按位取反、左移、右移等,同时详细解析它们的用法和实现原理,并通过实例演示如何应用位运算符来解决程序中的实际问题。此外,本文还将分析位运算符的优缺点,展示它们在编程中的一些常见应用场景,以及实现位运算的相关类和方法。

Java之位运算符

简介

  Java中的位运算符是用来对二进制数进行运算的。在进行位运算时,首先需要将数值转换为二进制,然后对它们进行特定的计算,最后将结果转换回十进制数。Java中的位运算符有六种,分别为按位与(&)、按位或(|)、按位异或(^)、按位取反(~)、左移(<<)、右移(>>),下面将分别讲解其用法和实现原理。

按位与(&)

  按位与运算符(&)的作用是将操作数的每个对应位都进行与运算,结果位的值为1只有当两个操作数对应位都为1时才会出现。例如:

代码语言:java复制
int a = 5; //101二进制表示
int b = 3; //011二进制表示

int result = a & b; //001二进制表示,即1

按位或(|)

  按位或运算符(|)的作用是将操作数的每个对应位都进行或运算,结果位的值为1只要有一个操作数对应位为1就会出现。例如:

代码语言:java复制
int a = 5; //101二进制表示
int b = 3; //011二进制表示

int result = a | b; //111二进制表示,即7

按位异或(^)

  按位异或运算符(^)的作用是将操作数的每个对应位都进行异或运算,结果位的值为1只有当两个操作数对应位不同才会出现。例如:

代码语言:java复制
int a = 5; //101二进制表示
int b = 3; //011二进制表示

int result = a ^ b; //110二进制表示,即6

按位取反(~)

  按位取反运算符(~)的作用是将操作数的每个对应位都进行取反操作(0变成1,1变成0)。例如:

代码语言:java复制
int a = 5; //101二进制表示

int result = ~a; //即010二进制表示,即-6

  需要注意的是,按位取反运算符(~)的结果是一个负数。

左移(<<)

  左移运算符(<<)的作用是将操作数的二进制位向左移动指定的位数,空位补0。例如:

代码语言:java复制
int a = 5; //101二进制表示

int result = a << 2; //即10100二进制表示,即20

右移(>>)

  右移运算符(>>)的作用是将操作数的二进制位向右移动指定的位数,空位的值由符号位决定,正数补0,负数补1。例如:

代码语言:java复制
int a = 20; //10100二进制表示

int result = a >> 2; //即00101二进制表示,即5

  需要注意的是,右移运算符(>>)会保留符号位,因此对于负数来说,右移运算会使结果变小,而对于正数来说,右移运算会使结果变大。

源代码解析

  下面是一些实际使用位运算符的Java源代码,演示了它们的具体用法:

按位与(&)

代码语言:java复制
public class Test {
    public static void main(String[] args) {
        int a = 5; //101二进制表示
        int b = 3; //011二进制表示

        int result = a & b; //001二进制表示,即1
        System.out.println(result);
    }
}

代码解析:

  这段代码表示对两个整数变量a和b进行按位与运算。具体来说,a和b的二进制表示分别为101和011,进行按位与运算后,得到的二进制结果为001,即1,将该结果赋值给result变量,然后输出result变量的值,即1。因此,该段代码的输出结果为1。

按位或(|)

代码语言:java复制
public class Test {
    public static void main(String[] args) {
        int a = 5; //101二进制表示
        int b = 3; //011二进制表示

        int result = a | b; //111二进制表示,即7
        System.out.println(result);
    }
}

代码解析:

  这段代码定义了一个Test类,包含了main方法。在main方法中,首先定义了两个整型变量a和b,分别赋值为5和3。

  然后使用位运算符“|”对变量a和b进行位或操作,将它们的二进制表示对应位上的值分别进行或运算,得到的结果为7,即111二进制表示。

  最后,使用System.out.println()方法输出结果7。因此,程序的输出结果为7。

按位异或(^)

代码语言:java复制
public class Test {
    public static void main(String[] args) {
        int a = 5; //101二进制表示
        int b = 3; //011二进制表示

        int result = a ^ b; //110二进制表示,即6
        System.out.println(result);
    }
}

代码解析:

  此代码是一个简单的Java程序,它定义了一个名为Test的公共类,其中有一个名为main的公共静态void方法,该方法在程序运行时被调用。

  在main方法中,定义了两个整型变量a和b,分别赋值为5和3。接下来,使用异或运算符^对a和b进行异或运算,并将结果赋值给result变量。异或运算的规则是,如果两个位上的值相同,则结果为0,否则为1。将a和b转换为二进制后,可以知道它们的二进制表示分别为101和011。将它们按位进行异或运算,得到的结果为110,也就是二进制的6。

  最后,程序将结果打印到控制台上,输出为6。

按位取反(~)

代码语言:java复制
public class Test {
    public static void main(String[] args) {
        int a = 5; //101二进制表示

        int result = ~a; //即010二进制表示,即-6
        System.out.println(result);
    }
}

代码解析:

  这段代码演示了Java中的按位取反运算符(~) 的用法。该运算符将操作数的二进制表示中的每个位取反,即0变为1,1变为0。在该代码中,变量a被赋值为5,其二进制表示为101。因此,按位取反运算符将其转换为010,即2的补码表示。该结果在Java中被解释为带符号的整数,因此其数值为-6。因此,当该程序运行时,~a的值为-6,并被打印到控制台上。

左移(<<)

代码语言:java复制
public class Test {
    public static void main(String[] args) {
        int a = 5; //101二进制表示

        int result = a << 2; //即10100二进制表示,即20
        System.out.println(result);
    }
}

代码解析:

  这段代码定义了一个名为Test的公共类,其中包含了一个名为main的公共静态方法。

  在main方法中,定义了一个整数变量a并赋值为5,即二进制表示为101。

  然后使用位运算符<<对a进行左移2位操作,将结果赋值给一个名为result的整数变量。左移运算符<<将二进制数向左移动指定的位数,并在低位补零。即将101左移2位得到10100,即20十进制表示。

  最后,使用System.out.println()方法将result的值输出到控制台。

  因此,程序运行后将输出20。

右移(>>)

代码语言:java复制
public class Test {
    public static void main(String[] args) {
        int a = 20; //10100二进制表示

        int result = a >> 2; //即00101二进制表示,即5
        System.out.println(result);
    }
}

代码解析:

  这段代码实现了将一个整数a右移两位的操作,并将结果输出。

  首先,定义了一个整型变量a并赋值为20,即二进制表示为10100。接着,使用右移运算符(>>)将a向右移动了两位,即将a中的每一位向右移动两位,并将空出来的两位补零。这样,a的二进制表示就变成了00101,即十进制的5。最后,将结果5输出。

应用场景案例

位运算符在Java开发中有很多实际应用场景,下面列举一些比较常见的应用案例:

奇偶性判断

  判断一个数是奇数还是偶数,可以使用按位与运算符(&)。因为偶数的二进制末位为0,奇数的二进制末位为1,因此可以将给定的数值与1进行按位与运算,如果结果为0,则是偶数,否则是奇数。例如:

代码语言:java复制
public class Test {
    public static boolean isEven(int num) {
        return (num & 1) == 0; //如果结果为0,则是偶数,否则是奇数
    }

    public static void main(String[] args) {
        System.out.println(isEven(4)); //输出true
        System.out.println(isEven(5)); //输出false
    }
}

代码解析:

  该代码定义了一个名为Test的类,包含了一个静态方法isEven。isEven方法接收一个参数num,返回一个布尔值。如果num为偶数,返回true,否则返回false。

  isEven方法的实现是利用位运算的性质:偶数的二进制末位为0,奇数的二进制末位为1。使用与运算(&)将num与1进行运算,如果结果为0,则num是偶数,否则是奇数。

  在main方法中,分别调用isEven方法,并输出其返回值,可以得到4是偶数,5是奇数的结论。

交换两个数的值

  交换两个数的值可以使用按位异或运算符(^)。因为异或运算规则是:两个二进制位不同则结果为1,相同则为0,因此可以通过异或运算来交换两个数的值,同时不需要使用额外的变量。例如:

代码语言:java复制
public class Test {
    public static void swap(int a, int b) {
        a ^= b; //a = a ^ b
        b ^= a; //b = b ^ (a ^ b) = a ^ b ^ b = a
        a ^= b; //a = (a ^ b) ^ a = b

        System.out.println("a = "   a   ", b = "   b);
    }

    public static void main(String[] args) {
        swap(5, 3); //输出a = 3, b = 5
    }
}

代码解析:

  这段代码实现了不使用第三个变量来交换两个整数的值。它使用了位运算中的异或操作(^)来达到目的。

  首先,将a和b进行异或操作,得到结果保存在a中:a = a ^ b。然后,将b和(a ^ b)进行异或操作,得到结果保存在b中:b = b ^ (a ^ b) = a ^ b ^ b = a。最后,再次将a和b进行异或操作,得到结果保存在a中:a = (a ^ b) ^ a = b。

  这样,a和b的值就被成功地交换了。在main函数中,调用swap函数,传入参数5和3,输出结果为a = 3, b = 5。

字符串的快速比较

  Java中的字符串比较通常使用equals()方法,但是这种方式效率比较低,因为它需要逐个比较每个字符,而使用位运算符可以快速比较两个字符串是否相等。具体实现是将两个字符串的每个字符按位异或,然后将所有结果按位与运算,如果结果为0,则表示两个字符串相等。例如:

测试代码演示
代码语言:java复制
package com.example.javase.se.operators;

/**
 * @Author ms
 * @Date 2023-11-07 22:30
 */
public class BitwiseOperatorDemo {

    public static boolean isEqual(String str1, String str2) {
        if (str1 == null || str2 == null || str1.length() != str2.length()) {
            return false;
        }

        int result = 0;
        for (int i = 0; i < str1.length(); i  ) {
            result ^= str1.charAt(i) ^ str2.charAt(i);
        }

        return result == 0;
    }

    public static void main(String[] args) {
        System.out.println(isEqual("hello", "hello")); //输出true
        System.out.println(isEqual("hello", "world")); //输出false
    }
}
测试结果

  根据如上测试用例,本地测试结果如下,仅供参考,你们也可以自行修改测试用例或者添加更多的测试数据或测试方法,进行熟练学习以此加深理解。

在这里插入图片描述在这里插入图片描述
测试代码分析

  根据如上测试用例,在此我给大家进行深入详细的解读一下测试代码,以便于更多的同学能够理解并加深印象。

  这段代码实现了一个比较两个字符串是否相等的方法。它使用了位运算符,具体来说是异或运算符(^)。

  方法 isEqual() 接收两个字符串参数,如果其中任意一个字符串为空或者两个字符串长度不相等,就返回 false。否则,它会对两个字符串的每个字符进行异或运算,并将结果保存到 result 变量中。如果最终 result 等于 0,说明两个字符串相等,返回 true;否则返回 false。

  在 main() 方法中,使用 isEqual() 方法比较了两组字符串,结果分别是 true 和 false。

优缺点分析

  位运算符的主要优点是效率高,可以快速处理整数类型的数据。另外,位运算符还可以用来进行特定的数据操作,比如判断奇偶性、交换两个数的值、字符串比较等,能够提高代码的灵活性和可读性。

  然而,位运算符的主要缺点是可读性不够好,因为操作的都是二进制位,需要进行繁琐的转换计算,容易出现错误。同时,位运算符在处理负数时需要特别注意符号位的处理,容易引起错误。

相关类和方法

  Java中提供了一些相关的类和方法来实现位运算的功能,下面简单介绍一些常用的:

  • Integer类:Java中的Integer类提供了一些方法来进行位运算,比如bitCount()方法可以计算一个整数的二进制表示中1的个数,highestOneBit()方法可以返回一个整数的最高位1的位置等等。
  • BitSet类:Java中的BitSet类实现了一套位向量的操作方法,可以方便地对二进制位进行操作,包括设置、清除、翻转、查找等。
  • Math类:Java中的Math类提供了一些方法来进行数值计算,其中包括了位运算相关的方法,比如max()和min()方法可以返回两个整数中的最大值和最小值,还有abs()方法可以返回一个整数的绝对值。

小结

  本文介绍了Java中的位运算符,包括按位与、按位或、按位异或、按位取反、左移、右移等。同时还详细解析了它们的用法和实现原理,并通过实例演示如何应用位运算符来解决程序中的实际问题。此外,本文还分析了位运算符的优缺点,展示了它们在编程中的一些常见应用场景,以及实现位运算的相关类和方法。最后,建议在使用位运算符时一定要仔细确认数据的符号位和二进制位,避免出现错误。

总结

  本文介绍了Java中的位运算符,包括按位与、按位或、按位异或、按位取反、左移、右移等。同时还详细解析了它们的用法和实现原理,并通过实例演示如何应用位运算符来解决程序中的实际问题。此外,本文还分析了位运算符的优缺点,展示了它们在编程中的一些常见应用场景,以及实现位运算的相关类和方法。在使用位运算符时,需要仔细确认数据的符号位和二进制位,避免出现错误。如果想学习Java编程,掌握位运算符是非常重要的一步。

... ...

文末

好啦,以上就是我这期的全部内容,如果有任何疑问,欢迎下方留言哦,咱们下期见。

... ...

学习不分先后,知识不分多少;事无巨细,当以虚心求教;三人行,必有我师焉!!!

wished for you successed !!!


⭐️若喜欢我,就请关注我叭。

⭐️若对您有用,就请点赞叭。

⭐️若有疑问,就请评论留言告诉我叭。

我正在参与2023腾讯技术创作特训营第三期有奖征文,组队打卡瓜分大奖!

0 人点赞