深入理解Java中的位运算符

哈喽,各位小伙伴们,你们好呀,我是喵手。运营社区:C站/掘金/腾讯云;欢迎大家常来逛逛

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

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

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

前言

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

摘要

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

Java之位运算符

简介

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

按位与(&)

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

int a = 5; //101二进制表示
int b = 3; //011二进制表示

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

按位或(|)

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

int a = 5; //101二进制表示
int b = 3; //011二进制表示

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

按位异或(^)

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

int a = 5; //101二进制表示
int b = 3; //011二进制表示

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

按位取反(~)

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

int a = 5; //101二进制表示

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

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

左移(<<)

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

int a = 5; //101二进制表示

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

右移(>>)

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

int a = 20; //10100二进制表示

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

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

源代码解析

  下面是一些实际使用位运算符的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。

按位或(|)

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。

按位异或(^)

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。

按位取反(~)

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,并被打印到控制台上。

左移(<<)

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。

右移(>>)

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,则是偶数,否则是奇数。例如:

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,因此可以通过异或运算来交换两个数的值,同时不需要使用额外的变量。例如:

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,则表示两个字符串相等。例如:

测试代码演示
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 !!!


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

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

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/677373.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Python深度学习基于Tensorflow(15)OCR验证码 文本检测与识别实例

文章目录 文本检测文本识别CTC层生成验证码并制作数据集建立模型模型推理 参考 文本检测 文本检测和目标检测类似&#xff0c;其不同之处在于文本目标具有序列特征&#xff0c;有连续性&#xff0c;可以通过结合 Faster R-CNN 和 LSTM 的方式进行文本检测&#xff0c;如 CTPN …

Android Graphics 显示系统 - Android Jank detection with FrameTimeline

“ 最近有公司同事在处理UI卡顿及FPS自动化监测的问题&#xff0c;我也顺便看了一点相关的内容&#xff0c;其中在Perfetto的官方说明文档中有一篇关于利用FrameTimeLine进行Jank监测的解读&#xff0c;个人觉得蛮有意思的&#xff0c;借助工具翻译该篇文章并加上本人拙劣的解读…

linux(centos7)开机自启jar文件

问题 之前参考网上说的直接在/etc/rc.local文件中增加sh文件启动语句&#xff0c;但是没有效果&#xff1a; /root/dashboard/dashboard_backend/start_dashboard.sh 权限也增加了&#xff0c;还是不行&#xff1a; chmod x /etc/rc.local 排查 排查了一下&#xff1a; 查…

基于聚类和回归分析方法探究蓝莓产量影响因素与预测模型研究附录

&#x1f31f;欢迎来到 我的博客 —— 探索技术的无限可能&#xff01; &#x1f31f;博客的简介&#xff08;文章目录&#xff09; 目录 背景数据说明数据来源思考 附录数据预处理导入包以及数据读取数据预览数据处理 相关性分析聚类分析数据处理确定聚类数建立k均值聚类模型 …

FFmpeg播放器的相关概念【1】

播放器框架 相关术语 •容器&#xff0f;文件&#xff08;Conainer/File&#xff09;&#xff1a;即特定格式的多媒体文件&#xff0c;比如mp4、flv、mkv等。 • 媒体流&#xff08;Stream&#xff09;&#xff1a;表示时间轴上的一段连续数据&#xff0c;如一段声音数据、一段…

BIOS主板(非UEFI)安装fedora40的方法

BIOS主板(非UEFI)安装fedora40的方法 现实困难&#xff1a;将Fedora-Workstation-Live-x86_64-40-1.14.iso写入U盘制作成可启动U盘启动fedora40&#xff0c;按照向导将fedora40安装到真机的sda7分区中得到报错如下内容&#xff1a; Failed to find a suitable stage1 device: E…

氯气安全阀检测流程揭秘:保障化工安全新举措

在化工行业中&#xff0c;氯气作为一种重要的工业原料&#xff0c;广泛应用于多个生产领域。 然而&#xff0c;氯气的危险性也不容忽视&#xff0c;一旦发生泄漏或超压等安全事故&#xff0c;后果不堪设想。因此&#xff0c;氯气安全阀的重要性便显得尤为突出。 在这篇文章中…

WindowManager相关容器类

窗口中容器类介绍&#xff1a; 本节内容较多&#xff0c;建议结合前面的内容一起阅读&#xff1a; 1、addWindow的宏观概念 2、WindowManager#addView_1 3、WindowManager#addView_2 1&#xff09;、WindowContainer&#xff1a; class WindowContainer<E extends WindowC…

Python编程基础2

文件对象&#xff1a; open内建函数&#xff1a;通过了初始化输入、输出&#xff08;I/O&#xff09;操作的通用接口&#xff0c;成功打开文件后会返回一个文件对象&#xff0c;否则引发错误。file_objectopen&#xff08;file_name&#xff0c;mode‘r’&#xff09;:file_nam…

一款仅200kb好看的免费引导页源码

源码介绍: 这是一款200kb左右的引导页,超级好看,用服务器或者主机均可搭建 下载压缩包解压至根目录即可&#xff0c;页面内容在index.html里修改 左边图片采用的是API接口&#xff08;不喜欢可以自行更换,在66/67行&#xff09; 引导页压缩包放在下面了,有需要的朋友可以直接下…

【热点】老黄粉碎摩尔定律被,量产Blackwell解决ChatGPT耗电难题

6月3日&#xff0c;老黄又高调向全世界秀了一把&#xff1a;已经量产的Blackwell&#xff0c;8年内将把1.8万亿参数GPT-4的训练能耗狂砍到1/350&#xff1b; 英伟达惊人的产品迭代&#xff0c;直接原地冲破摩尔定律&#xff1b;Blackwell的后三代路线图&#xff0c;也一口气被…

杂谈k8s

其实看我之前的博客&#xff0c;k8s刚有点苗头的时候我就研究过&#xff0c;然后工作的时候间接接触 也自己玩过 但是用的不多就忘记了&#xff0c;正苦于不知道写什么&#xff0c;水一篇 简化容器应用程序的部署和管理 自动化部署、自动伸缩、负载均衡、存储管理、自我修复 支…

DP-Kmaens密度峰值聚类算法

我有个问题 关于 [密度值>密度阈值] 的判定这里&#xff0c;新进来的新数据怎么确定他的密度值&#xff1f;密度阈值又是怎样确定的呢&#xff1f;

Golang | Leetcode Golang题解之第129题求根节点到叶节点数字之和

题目&#xff1a; 题解&#xff1a; type pair struct {node *TreeNodenum int }func sumNumbers(root *TreeNode) (sum int) {if root nil {return}queue : []pair{{root, root.Val}}for len(queue) > 0 {p : queue[0]queue queue[1:]left, right, num : p.node.Left, …

RPM包方式离线部署gitlab

下载安装包 要求&#xff1a;可以联网&#xff0c;系统及版本与目标服务器一致。配置gitlab yum仓库 curl -s https://packages.gitlab.com/install/repositories/gitlab/gitlab-ce/script.rpm.sh | sudo bash 新建包存放目录 mkdir /root/gitlab 下载gitlab及相关安装包 …

Linux之线程及线程安全详解

前言&#xff1a;在操作系统中&#xff0c;进程是资源分配的基本单位&#xff0c;那么线程是什么呢&#xff1f;线程是调度的基本单位&#xff0c;我们该怎么理解呢&#xff1f; 目录 一&#xff0c;线程概念理解 二&#xff0c;Linux里面的线程原理 三&#xff0c;为什么要…

《MySQL索引》学习笔记

《MySQL索引》学习笔记 MySQL的体系结构存储引擎简介InnoDB简介MyISAM简介 索引索引结构BTreeHash索引思考索引分类 索引语法SQL性能分析索引使用最左前缀法则 索引失效的情况范围查询索引列运算字符串不加引号模糊查询or连接的条件数据分布影响 SQL提示覆盖索引前缀索引单列索…

【MyBatisPlus】DML编程控制

【MyBatisPlus】DML编程控制 文章目录 【MyBatisPlus】DML编程控制1、id生成策略2、逻辑删除 1、id生成策略 id生成策略控制&#xff08;TableId注解&#xff09; 名称&#xff1a;TableId 类型&#xff1a;属性注解 位置&#xff1a;模型类中用于表示主键的属性定义上方 作…

机器学习中的集成学习

&#x1f4ac;内容概要 1 集成学习概述及主要研究领域 2 简单集成技术  2.1 投票法  2.2 平均法  2.3 加权平均 3 高级集成技术  3.1 Bagging  3.2 Boosting  3.3 Bagging vs Boosting 4 基于Bagging和Boosting的机器学习算法  4.1 sklearn中的Bagging算法  4.2 sklea…

AI大模型探索之路-实战篇15: Agent智能数据分析平台之整合封装Tools和Memory功能代码

系列篇章&#x1f4a5; AI大模型探索之路-实战篇4&#xff1a;深入DB-GPT数据应用开发框架调研 AI大模型探索之路-实战篇5&#xff1a;探索Open Interpreter开放代码解释器调研 AI大模型探索之路-实战篇6&#xff1a;掌握Function Calling的详细流程 AI大模型探索之路-实战篇7…