Java语言位运算符详解

简介: Java语言提供了7种位运算符:按位与(&)、按位或(|)、按位异或(^)、取反(~)、左移(<<)、带符号右移(>>)和无符号右移(>>>)。这些运算符主要用于对long、int、short、byte和char类型的数据进行二进制位级别的操作,不能用于double、float和boolean类型。文中详细讲解了每种运算符的规则和应用场景,并指出位运算在实际开发中有重要应用价值,不仅限于面试。

很多编程语言都有位运算符,Java语言也不例外。在Java语言中,提供了7种位运算符,分别是按位与(&)、按位或(|)、按位异或(^)、取反(~)、左移(<<)、带符号右移(>>)和无符号右移(>>>)。这些运算符当中,仅有~是单目运算符,其他运算符均为双目运算符。在讲解这些运算符的使用之前,必须了解一个常识,那就是:位运算符是对long、int、short、byte和char这5种类型的数据进行运算的,我们不能对double、float和boolean进行位运算操作。下面就来详细讲解这7种位运算符的使用方法。

一、按位与运算符

按位与运算符的写法是一个”&”符号,与”不短路的逻辑与运算符”写法是完全一样的,但意义不同。逻辑与运算是对布尔型数据进行运算,而按位与运算是对二进制位上的数值进行计算。按位与运算符的运算规则如下图所示:

运算规则总结成一句话就是:如果两个二进制位上的数都是1,那么运算结果为1,其他情况运算结果均为0。下面举例说明按位与运算符的运算过程,我们用数字5和6进行按位与运算。这个过程可以用下图表示:

运算过程中,首先把5和6这两个数字转换为补码,之后还要把这两个数字按位对齐,然后一一把两个相应的二进制位上的数字进行按位与运算,运算得到的二进制串就是最终的结果。按照补码反向转换为十进制数字的规则,可以计算出5&6的运算结果是4。在这里要提醒大家一句:进行位运算的时候,最左边的符号位也是要参与运算的。

二、按位或运算符

按位或运算符的写法是一个”|”符号,与”不短路的逻辑或运算符”写法相同,它的运算规则也很简单,如下图所示:

运算规则概括成比较好记的一句话就是:两个二进制位上的数字如果都为0,那么运算结果为0,否则运算结果是1。同按位与运算一样,符号位也要参与运算。下面我们还是用5和6为例来讲解一下按位或的运算过程,如下图所示:

首先还是把这两个数字转换成补码形式,之后把相应的二进制位上的数字进行按位或运算:如果两个二进制数都是0,计算结果为0,其他情况计算结果均为1。按照这个规则把每一位上的数字都计算一遍后,得到二进制的运算结果是111,这个运算结果转换为十进制数是7。

三、按位异或运算符

按位异或运算符写法是”^”,它的运算规则如下图:

如上图,运算规则为:两个二进制位上的数字如果相同,则运算结果为0,如果两个二进制位上的数字不相同,则运算结果为1。下面我们还是用5和6为例来讲解一下异或的运算过程,如下图:

首先还是把这两个数字转换成补码形式,之后把相应的二进制位上的数字进行异或运算,如果对应的两个二进制位上的数相同,计算结果为0,否则计算结果为1。按照这个规则把每一位上的数字都计算一遍后,得到二进制的运算结果是11,这个运算结果转换为十进制数是3。

关于异或运算符,有很多非常有用的特性,我们在这里梳理总结一下。

Ⅰ、异或运算符满足交换律

也就是说,a^b与b^a是等价的,虽然a和b交换了位置,但还是会运算出相同的结果。这个规律还可以推广到N个操作数,也就是说,如果有N个变量都参与了异或运算,那么它们的位置无论如何交换,运算的结果都是相同的。

Ⅱ、任何两个相同的数字进行异或操作,所得到的结果都必然为0

这个特性并不难理解,因为两个相同的数字,换算成补码后,每个二进制位上的数也都相同,这样在进行异或运算时,按照运算规则,每个二进制位上得到的运算结果也都是0,这N个0所组成的二进制串就是数字0的补码。我们可以利用这个特性快速的判断两个整数是否相同。另外,利用这个特性还可以实现内存的快速清零操作,比如我们可以在代码中写上a=a^a;这条语句能快速的把变量a所占据的那几个字节的内存迅速清零。

Ⅲ、对于任意一个二进制位来说,这个位上的数与0进行异或运算,运算结果与这个二进制位上的数是相同的,而与1进行异或运算,结果与这个二进制位上的数字相反

注意,我们现在说的是二进制位上的数字,所谓相反不是说原来这个位上是1,运算结果是-1,而是说原来是1,运算结果为0,原来如果是0,运算结果是1,这才是此处所说的”相反”的概念。这个特性也非常好理解,小伙伴们一定要记住它,在以后进行一些位运算操作的时候经常会用到这个特性。

、对于任何两个整数a和b,a^b^b等于a

这个结论为什么成立呢?简单说来,就是因为这个表达式中有b^b,而b^b的结果为0,前文已讲过,任何一个数与0进行按位异或操作,结果仍然是这个数本身,所以,a^b^b等于a。这个特性在加密运算方面有着很普遍的应用。我们可以把a当作要加密的数据,而把b当作密钥。a异或b就是把a用密钥b进行了加密操作,当需要解密时,仍然以b作为密钥,再进行一次异或就实现了解密。

这个特性还可以推出另外一个结论:对于任何两个整数a和b,a^b^a等于b。我们能够得到这个结论的原因也很简单,就是因为按照交换律,a^b与b^a的运算结果是一样的,所以a^b^a等价于b^a^a,这个表达式中出现了a^a,a^a的值也为0,所以整个表达式的其实就相当于b^0,最终结果还是b。

希望大家能够牢记以上这些结论,在后续的文章中,会讲解如何用这些结论去解决实际问题。

四、按位取反运算符

按位取反运算符写法是”~”,它的运算规则是:对每个二进制位进行取反操作,所谓取反就是原来二进制位上如果是0,那么就变成1,反之,如果原来二进制位上是1,那么就变为0。取反运算符是一个单目运算符,所以只需要一个操作数就可以了。我们以数字5为例讲解按位取反的运算过程:

首先把数字5转换成补码形式,之后把每个二进制位上的数字进行取反,如果是0就变成1,如果1就变成0,经过取反后得到的二进制串就是运算结果,这个运算结果被还原为十进制数是-6。取反运算符的运算规则也非常容易理解,但是在这里老师需要提醒各位读者注意:如果是对变量进行取反操作,那么经过操作之后,变量的值并不会发生变化!为方便小伙伴们理解,请看下图:

从程序运行的结果可以看出:输出a的值还是5,这说明变量a经过取反得到的那个-6并没有被赋值到变量a中,通过这个例子可以证明,取反运算并没有对变量重新赋值的功能,取反运算的结果只是临时保存在操作数栈中,变量本身的值不会因取反操作而发生改变。

下面再来讲解一下与位移相关的运算符。所谓”位移”就是指在内存中对二进制串进行移动的操作。只要是移动操作,就必然会涉及到以下几个问题,怎样表示移动方向?怎样表示移动的位数?移动之后空出来的二进制位用什么来填充?移动之后跑到原来内存单元外面的那些数字怎么处理?符号位要不要跟着一起移动?这些问题都是我们学习位移操作要弄清楚的细节。各位小伙伴可以带着这些问题来学习位移相关的运算符。与位移相关的运算符有三个,分别是左移(<<)、带符号右移(>>)、无符号右移(>>>)。

五、左移运算符

左移运算符的写法是”<<“,看上去向两个向左的箭头,表示要把二进制数据在内存空间中向左边移动。使用左移运算符时,把想进行位移操作的操作数放最左面,之后写上左移运算符,在左移运算符的右边写上移动的位数。例如:5<<2就表示对数字5进行左移2位的操作。下图展示了进行左移操作之后,二进制串在内存中是怎样变化的:

可以看到这个二进制串在内存中整体向左移动了两位,那么最左边的两位就跑到内存单元的外面去了,这两位数字将会被舍弃,右边空出的两位用0补齐。

左移运算有乘以2的N次方的效果。一个数向左移动1位,就相当于乘以2的1次方,移动两位就相当于乘以2的2次方,也就是乘以4。位移操作在实际运算时远远快于乘法操作,所以在某些对运算速度要求非常高的场合,可以考虑用左移代替乘以2的N次方的乘法操作。但是需要提醒大家注意三个细节:

首先:位移操作同取反操作一样,并不能改变变量本身的值,所能改变的仅是存储在操作数栈中那个数据的值,不理解这句话意思的小伙伴看下图:

其次:当位移的位数很多时,导致最左边的符号位发生变化,就不再具有乘以2的N次方的效果了。比如十进制的5转换为补码形式是:前面29个0最后3位是101,如果移动29位,那么最前面的符号位就变成了1,此时运算的结果就成为了一个负数,不再是5乘以2的29次方的乘法结果。

最后:对于byte/short/int三种类型的数据,Java语言最多支持31位的位移运算,对于long类型的数据而言,最多支持63位的位移运算。这可能是因为Java语言的设计者认为位移的偏移量已经超过存储数据本身的长度,没有什么意义。小伙伴们可以试一下数字5左移32位是什么结果。

六、带符号右移运算符

右移运算分为两种,分别是带符号右移和无符号右移。首先我们来说说带符号右移运算符。带符号右移运算符的写法是”>>“,与左移运算符的方向恰好相反。所谓带符号右移就是指当二进制串向右边移动以后,左边空出的位用”符号位上的数字”填充,说的更直白一点,如果是正数,二进制串右移的时候用0来填充左边的空位,而对于负数而言,右移的时候用1来填充左边的空位,如下图:

从图上可以清楚的看到带符号右移操作在二进制串移动之后左边空位是怎样被填充的。之前强调过,左移操作具有乘以2的N次方的效果,其实带符号右移也具有”类似”除以2的N次方的效果。请注意,这里说的是”类似”除以2的N次方的效果,为什么要加上”类似”两个字呢?就是因为对于正数而言,带符号右移之后产生的数字确实等于除以2的N次方,但是对于负数而言,带符号右移是在除以2的N次方的结果之上还要减去1。比如对于正5,带符号右移两位的结果是1,而对于-5,带符号右移两位的结果是-2,也就是-5被2的2次方整除再减去1的结果。

带符号右移的操作可以保证移动之前和移动之后数字的正负属性不变,原来是正数,不管移动多少位,移动之后还是正数,原来是负数,移动之后还是负数。另外,我们还可以继续深挖一下这个特性,从而得到一个结论:对于任何一个byte、short或者int类型的数据而言,带符号右移31位之后,得到的必然是0或者是-1。对于long类型的数据而言,带符号右移63位之后,得到的也必然是0或者是-1。能够得出这个结论的依据也很简单,就是因为对于byte、short和int类型的变量而言,如果是正数,带符号右移31位之后产生的二进制串必然全部是0,转换成对应的十进制数就是0;而对于负数而言,带符号右移31位之后产生的二进制串必然全部是1,转换成十进制数就是-1。对于long类型的数据,带符号右移63位也具有相同效果。

七、无符号右移运算符

前文已说过:右移运算分为两种,分别是带符号右移和无符号右移。现在再来讲解无符号右移。无符号右移运算符的写法是”>>>”,比带符号右移多了一个”>”。带符号右移的运算规则与无符号右移的运算规则差别就在于:无符号右移在二进制串移动之后,空位由0来补充,与符号位是0还是1毫无关系,如下图:

以上图片展示了无符号右移的运算规则。对于正数而言,无符号右移和带符号右移没有什么区别,而对于负数而言,经过无符号右移会产生一个正数,因为最左边的符号位被0填充了。

到此为止,我们已经讲解了全部的7个位运算符。很多小伙伴都会认为位运算没有太多的实用价值,学习位运算操作也只是为了应付面试。其实这种想法是完全错误的。位运算在很多场合都有着深入应用,能够解决很多实际问题。随后的几篇文章将详细讲解位运算在实际开发中的应用技巧。


转载来源:https://juejin.cn/post/6844904100295868423

相关文章
|
9天前
|
人工智能 安全 Java
智慧工地源码,Java语言开发,微服务架构,支持分布式和集群部署,多端覆盖
智慧工地是“互联网+建筑工地”的创新模式,基于物联网、移动互联网、BIM、大数据、人工智能等技术,实现对施工现场人员、设备、材料、安全等环节的智能化管理。其解决方案涵盖数据大屏、移动APP和PC管理端,采用高性能Java微服务架构,支持分布式与集群部署,结合Redis、消息队列等技术确保系统稳定高效。通过大数据驱动决策、物联网实时监测预警及AI智能视频监控,消除数据孤岛,提升项目可控性与安全性。智慧工地提供专家级远程管理服务,助力施工质量和安全管理升级,同时依托可扩展平台、多端应用和丰富设备接口,满足多样化需求,推动建筑行业数字化转型。
47 5
|
6月前
|
存储 人工智能 算法
数据结构与算法细节篇之最短路径问题:Dijkstra和Floyd算法详细描述,java语言实现。
这篇文章详细介绍了Dijkstra和Floyd算法,这两种算法分别用于解决单源和多源最短路径问题,并且提供了Java语言的实现代码。
195 3
数据结构与算法细节篇之最短路径问题:Dijkstra和Floyd算法详细描述,java语言实现。
|
5月前
|
监控 Java API
如何使用Java语言快速开发一套智慧工地系统
使用Java开发智慧工地系统,采用Spring Cloud微服务架构和前后端分离设计,结合MySQL、MongoDB数据库及RESTful API,集成人脸识别、视频监控、设备与环境监测等功能模块,运用Spark/Flink处理大数据,ECharts/AntV G2实现数据可视化,确保系统安全与性能,采用敏捷开发模式,提供详尽文档与用户培训,支持云部署与容器化管理,快速构建高效、灵活的智慧工地解决方案。
|
1月前
|
Java 程序员 数据处理
课时19:Java运算符(位运算符)
课时19介绍Java中的位运算符,涵盖进制转换、位与、位或及移位操作。重点讲解了二进制与其他进制的转换方法,通过具体范例演示了位与和位或运算的过程,并展示了八进制和十六进制的处理方式。此外,还解释了逻辑运算符(&&、||)与位运算符(&、|)的区别及其应用场景,特别是位运算在加密中的应用。
|
2月前
|
存储 缓存 Java
java语言后台管理ruoyi后台管理框架-登录提示“无效的会话,或者会话已过期,请重新登录。”-扩展知识数据库中密码加密的方法-问题如何解决-以及如何重置若依后台管理框架admin密码-优雅草卓伊凡
java语言后台管理ruoyi后台管理框架-登录提示“无效的会话,或者会话已过期,请重新登录。”-扩展知识数据库中密码加密的方法-问题如何解决-以及如何重置若依后台管理框架admin密码-优雅草卓伊凡
260 3
java语言后台管理ruoyi后台管理框架-登录提示“无效的会话,或者会话已过期,请重新登录。”-扩展知识数据库中密码加密的方法-问题如何解决-以及如何重置若依后台管理框架admin密码-优雅草卓伊凡
|
3月前
|
Oracle Java 关系型数据库
Java基础(一):语言概述
Java基础(一):语言概述
98 15
Java基础(一):语言概述
|
3月前
|
Java
Java基础(四):逻辑运算符和位运算符
Java基础(四):逻辑运算符和位运算符
51 10
Java基础(四):逻辑运算符和位运算符
|
8月前
|
Java Maven
使用java语言制作一个窗体(弹窗),用来收集用户输入的内容
该博客文章介绍了如何使用Java Swing中的JFrame创建一个窗体来收集用户输入的内容,并提供了详细的实现步骤和完整代码示例。
使用java语言制作一个窗体(弹窗),用来收集用户输入的内容
|
2月前
|
缓存 Java 应用服务中间件
java语言后台管理若依框架-登录提示404-接口异常-系统接口404异常如何处理-登录验证码不显示prod-api/captchaImage 404 (Not Found) 如何处理-解决方案优雅草卓伊凡
java语言后台管理若依框架-登录提示404-接口异常-系统接口404异常如何处理-登录验证码不显示prod-api/captchaImage 404 (Not Found) 如何处理-解决方案优雅草卓伊凡
420 5
|
1月前
|
Java 开发者
课时2:Java语言特点
课时2介绍了Java语言的多个关键特性。作为开源且半开源的产品,Java成为通用技术标准,拥有透明的开发环境。其面向对象的设计、自动内存回收、简化指针处理(使用引用)、支持多线程编程、高效的网络处理能力(如NIO)及良好的可移植性,共同促成了Java的强大生态系统和广泛应用。
下一篇
oss创建bucket