Java 位运算符和移位运算符
参考:
Bitwise and Bit Shift Operators
《Java 编程思想 第3章 操作符》
今天学习 Java BitSet
类时,发现对于位运算符和移位运算符的操作有些陌生,所以重新复习一下
主要内容:
- 位操作浅析
- 位运算符
- 移位运算符
- 优先级
- 问题解析
- 取值范围
位操作浅析
Java
可在整数类型(integral type
)数据上进行位(bit
)操作
整数类型:
- 字节型(
byte
,8
位) - 短整型(
short
,16
位) - 整型(
int
,32
位) - 长整型(
long
,64
位)
原码,反码和补码
参考:
原码,反码和补码的关系?
原码、反码、补码的产生、应用以及优缺点有哪些?
首先原码,反码和补码都是基于二进制数进行的
对于正数而言,其原码,反码和补码一致(无符号数就是正数)
在 Java
中的整数类型都是有符号数,即其最高位为符号位(正数为 0
,负数为 1
)
默认情况下,二进制数就是原码表示,所以将十进制数 15
转换为二进制原码就是(假定为 8
位整数)
00001111
将十进制数 -15
转换为二进制原码就是
10001111
原码和反码相互转换规则:负数保留符号位不变,其它位按位取反
将十进制 -15
转换为二进制反码就是
11110000
原码和补码相互转换规则:负数符号位不变,其余位求反再加 1
将十进制 -15
转换为二进制补码就是
11110001
加减运算
在计算机中,使用补码保存整数类型数据(因为补码格式有利于计算机进行移位运算)
加减运算时,补码直接相加即可(符号位参与运算)
进制转换
Java
不能直接表示二进制整数,但可以表示成八进制(以数字 0
开头),十进制(没有前置)和十六进制(以数字 0
和 字符 x
开头),默认情况使用十进制计算
比如对于整数 15
来说,其八进制表示为 017
,十六进制表示为 0xf
通常情况下使用 十六进制 来表示 二进制
一个整型数据占 4
个字节,共 32
位,那么对于整型数 a = 15
来说,其二进制表示如下
// 前面共 28 个 0
0000...0001111
转换为十六进制,就是 0x0000000f
位运算符
Java
提供了 4
种位运算符
- 位与运算符(
bitwise and operator
):&
- 位或运算符(
bitwise inclusive or operator
):|
- 位异或运算符(
bitwise exclusive or operator
):^
- 位取反运算符(
bitwise invert operator
):~
这些运算符是在二进制补码上进行操作
测试程序如下:
public static void main(String[] args) {byte a = 15;byte b = -15;System.out.println(a & b);System.out.println(a | b);System.out.println(a ^ b);System.out.println(~a);System.out.println(~b);
}
一个字节数占 8
位,将 a
,b
转换为二进制:
a = 0000 1111
b = 1111 0001
Note:计算机使用补码表示
位与运算符:仅当两个操作数同一下标的值均为 1
时,结果才为 1
a & b = 0000 1111 & 1111 0001 = 0000 0001(补) = 0000 0001(原) = 1
位或运算符:只要两个操作数同一下标的值有一个为 1
时,结果就为 1
a | b = 0000 1111 & 1111 0001 = 1111 1111(补) = 1000 0001(原) = -1
位异或运算符:只有两个操作数同意下标的值不相等时,结果才为 1
a ^ b = 0000 1111 ^ 1111 0001 = 1111 1110(补) = 1000 0010(原) = -2
位取反运算符:按位取反每一位
~a = ~0000 1111 = 1111 0000(补) = 1001 0000(原) = -16
~b = ~1111 0001 = 0000 1110(补) = 0000 1110(原) = 14
Note 1:byte
或者 short
类型数值进行位运算后,返回的是 int
类型数值(没有找到资料说明在位运算之前是否已经进行了转换,不过先将 a
,b
转换为 int
类型二进制再进行计算的结果和上面一致)
Note 2:位运算符的操作不排除符号位
移位运算符
Java
提供了 3
种移位运算符
- 左移运算符(
left shift operator
):<<
- 右移运算符(
right shift operator
):>>
- 无符号右移运算符(
unsigned right shift operator
):>>>
示例程序如下:
public static void main(String[] args) {System.out.println("正数移位");compute(15);System.out.println("负数移位");compute(-15);
}public static void compute(int a) {println(a << 3);println(a << -61);println(a << 35);println(a >> 3);println(a >> -61);println(a >> 35);println(a >>> 3);println(a >>> -61);println(a >>> 35);
}public static void println(int n) {System.out.println(n);
}
对于移位运算符而言,左侧操作数表示要移动的二进制数,右侧操作数表示要移动的位数
进行移位操作时,需要注意以下几点:
对于
byte
或者short
类型数值,进行移位操作时,会先转换为int
类型,然后进行移位(如果是long
类型,则不变)对于右侧操作数而言,在进行移位之前,先转换为二进制数(补码)。如果左侧数是
int
类型,则取右侧操作数最右端5
位数值进行移动;如果是long
类型数值,则取右侧操作数最右端6
位数值进行移动
左移运算符:数值位向左移动指定位数
15 << 3 = 0x0000000f << 3 = 0x00000078(补,原) = 120
15 << -61 = 0x0000000f << 0xffffffc3(左侧是 int 类型,取右侧 5 位) = 0x0000000f << 3 = 0x00000078(补,原) = 120
15 << 35 = 0x0000000f << 0x00000023(左侧是 int 类型,取右侧 5 位) = 0x0000000f << 3 = 0x00000078(补,原) = 120-15 << 3 = 0xfffffff1 << 3 = 0xffffff88(补) = 0x80000078(原) = -120
-15 << -61 = 0xfffffff1 << 0xffffffc3(左侧是 int 类型,取右侧 5 位) = 0xfffffff1 << 3 = 0xffffff88(补) = 0x80000078(原) = -120
-15 << 35 = 0xfffffff1 << 0x00000023(左侧是 int 类型,取右侧 5 位) = 0xfffffff1 << 3 = 0xffffff88(补) = 0x80000078(原) = -120
右移运算符:数字位向右移动指定位数(如果左操作数是正数,高位补 0
;如果是负数,高位补 1
)
15 >> 3 = 0x0000000f >> 3 = 0x00000001 = 1
-15 >> 3 = 0xfffffff1 >> 3 = 0xfffffffe(补) = 0x80000002(原) = -2
无符号右移运算符:功能和右移运算符一样,不过无论正负,高位均补 0
15 >>> 3 = 0x0000000f >>> 3 = 0x00000001 = 1
-15 >> 3 = 0xfffffff1 >>> 3 = 0x1ffffffe(补,原) = 2^29 - 2 = 536870910
Note 1:移位运算时,从符号位开始操作
Note 2:由结果可知,左移一位相当于乘以2,右移一位相当于除以 2
优先级
参考:运算符优先级
Java
运算符优先级如下图所示:
由图中可知,位运算符和移位运算符的优先级从左到右如下:
~,<<,>>,>>>,&,^,|
问题解析
之前学习类 BitSet
时遇到了很多的位运算,但是有一些操作没搞明白,下面是我总结的一些问题和解答
问题一:移动位数超过其精度如何解决
- 解答:在进行移位操作之前,先将右侧数值转换成二进制(其实在计算机内部就是以二进制补码保存的)。如果左侧操作数为
int
类型数值,那么取右侧操作数的最右端5
位进行移位;或者左侧操作数是long
类型数值,取右侧操作数的最右端6
位进行移位
- 解答:在进行移位操作之前,先将右侧数值转换成二进制(其实在计算机内部就是以二进制补码保存的)。如果左侧操作数为
问题二:移动位数为负如何解决
- 解答:和问题一的解答一样,取右侧操作数的最右端
5/6
位进行移位
- 解答:和问题一的解答一样,取右侧操作数的最右端
问题三:如何解决符号位的问题
- 解答:计算机以二进制补码形式保存整型数值。
- 无论是加减 / 位运算 / 移位运算,符号位均参与其中
- 解答:计算机以二进制补码形式保存整型数值。
问题四:已知起始下标
fromIndex
和 终止下标toIndex
,如何在位集中设定这一段连续区间为true
解答:以
int
类型为例,位集长度为32
位,假设fromIndex = 3
,toIndex = 10
,那么示例程序如下:public static final int WORD_MASK = 0xffffffff;public static void main(String[] args) {int fromIndex = 3;int toIndex = 10;int firstWordMask = WORD_MASK << fromIndex;int lastWordMask = WORD_MASK >>> -toIndex;int res = (firstWordMask & lastWordMask);System.out.println(Integer.toBinaryString(firstWordMask));System.out.println(Integer.toBinaryString(lastWordMask));System.out.println(Integer.toBinaryString(res)); }
要设定位集中连续区间位值为
true
,可以设定一个辅助常量WORD_MASK
,保证每个位均为true
定义起始下标
fromIndex = 3
,结束下标toIndex = 10
计算
firstWordMask
,使得WORD_MASK
向左移动fromIndex
个位置,低位补0
,结果使得区间[0-fromIndex)
的位值为0
计算
lastWordMask
,使得WORD_MASK
向右移动n
个位置,高位补0
,结果使得区间(toIndex-32]
的位值为0
最后进行位与操作,得到区间
[fromIndex-toIndex]
的位值为true
Note:对于
int
值而言,设a = 3
,则取-3
的后5
位就是(32-3)=29
;若是long
值,取-3
的后6
位就是(64-3)=61
取值范围
字节类型占 8
位,其中最高位为符号位,所以其取值范围为 [-2^7-1,2^7-1] = [-127,127]
,其中 0
有两种表示方式
00000000 或者 10000000
将 10000000
当作 -128
,则 字节类型的取值为 [-128,127]
public static final byte MIN_VALUE = -128;
public static final byte MAX_VALUE = 127;
示例程序如下:
public static void main(String[] args) {System.out.println(Integer.toBinaryString(Byte.toUnsignedInt(Byte.MAX_VALUE)));System.out.println(Integer.toBinaryString(Byte.toUnsignedInt(Byte.MIN_VALUE)));
}
同理,短整型的取值范围为 [-2^15,2^15-1]
,整型的取值范围为 [-2^31,2^31-1]
,长整型的取值范围为 [-2^63,2^63-1]
// Short.java
public static final short MIN_VALUE = -32768;
public static final short MAX_VALUE = 32767;// Integer.java
@Native public static final int MIN_VALUE = 0x80000000;
@Native public static final int MAX_VALUE = 0x7fffffff;// Long.java
@Native public static final long MIN_VALUE = 0x8000000000000000L;
@Native public static final long MAX_VALUE = 0x7fffffffffffffffL;
示例程序如下:
public static void main(String[] args) {System.out.println(Integer.toBinaryString(Short.toUnsignedInt(Short.MAX_VALUE)));System.out.println(Integer.toBinaryString(Short.toUnsignedInt(Short.MIN_VALUE)));System.out.println(Integer.toBinaryString(Integer.MAX_VALUE));System.out.println(Integer.toBinaryString(Integer.MIN_VALUE));System.out.println(Long.toBinaryString(Long.MAX_VALUE));System.out.println(Long.toBinaryString(Long.MIN_VALUE));
}
Java 位运算符和移位运算符相关推荐
- Java位运算符和移位运算符详解
位运算符主要针对二进制,它包括了:"与"."非"."或"."异或". 移位运算符包括,"左移运算符" ...
- Java中的逻辑运算符/移位运算符简单总结
前段时间刷到了力扣关于位运算的题,这里浅浅记录一下! 1. 逻辑位运算 1.1 与 & &:按位与进行二进制计算,规则是同为1则为1,不同为0,具体如下: 0&0=0, 0&a ...
- python左移位运算_python移位运算符
1,二进制方式 >>> bin( 1)'0b1' >>> bin( 10)'0b1010' >>> a =0b10>>>a2 & ...
- 位运算符和移位运算符
位运算符 主要应用在二进制中运算中. 与(&)运算符 示例: 0&0=0 必须全部位1则为1,否则为0 0&1=0 1&0=0 1&1=1 全部为1,结果 ...
- Java位运算之移位运算
文章目录 移位运算 左移 << 位运算符 右移 >> 位运算符 无符号右移 >>> 运算符 移位运算 移位运算符在程序设计中,是位操作运算符的一种.移位运算符 ...
- python中移位运算符_python移位运算符
1,二进制方式 >>> bin( 1)'0b1' >>> bin( 10)'0b1010' >>> a =0b10>>>a2 & ...
- python左移位运算_python 移位运算符只能用于整型吗
匿名用户 1级 2016-12-29 回答 什么是操作符? 简单的回答可以使用表达式4 + 5等于9,在这里4和5被称为操作数,+被称为操符. Python语言支持操作者有以下几种类型. 算术运算符 ...
- Java中的位运算符、移位运算
一.位运算 Java中有4个位运算,它们的运算规则如下: (1)按位与 (&) :两位全为1,结果为1,否则为0: (2)按位或 (|) :两位有一个为1,结果为1,否则为0: (3) ...
- java中的位移运算符_java中的移位运算符(, , )
java中有3种移位运算符 < >> : 右移运算符,不改变符号位,num >> n 表示二进制右移n位,结果相当于 num / (2的n次方) >>&g ...
最新文章
- java中如何取到一个对象的所有属性值,并且在创建一个相同的对象
- kube-controller-manager 配置参数解读
- mysql下 ect p_Linux系统下启动MySQL的命令及相关知识
- Tomcat源码解析一:下载源码与导入eclipse
- java swing运行没反应_java – 无法从命令行运行swing
- You can't specify target table 'tablename' for update in FROM clause的解决方法
- 大数据项目开发案例_大数据开发相关术语解析
- layui文档通读笔记
- 服务器mdl文件转换,Simulink Project 中 MDL 到 SLX 模型文件格式的转换
- excel函数 不能正常显示数字
- 易班显示不能连接到服务器检查网络,网络思政教育 “易班网”不一般
- 使用html打开电脑前置摄像头并拍照
- M26X2 4G工业路由器的技术应用
- 英语六级试卷软件测试,大学英语六级考试预测试卷以及答案
- 移动apn接入点哪个快_电信和联通以及移动物联卡哪个较好
- 学会“狼”的思维(二)
- kdb+q一个入库和删除的小demo
- LWN:使用Rust实现OpenPGP,这就是Sequoia项目!
- Springboot 整合Websocket+Stomp协议+RabbitMQ做消息代理 实例教程
- 技术型产品经理的思维能力
热门文章
- VMC证书是什么?获取认证标志证书步骤是怎样的?
- Android设置悬浮窗按钮,图片有多余的白色背景
- 肝气郁结害处多(一)
- [转摘]测试用例设计—因果图法
- 2021年最新Web前端HTML,CSS,Vue,React,Jquery大概率面试题合集
- 在linux服务器上用ffmpeg进行视频转换
- Python抓包练习-Linux
- 飞机大战(wsad上下左右,空格发射子弹,击中敌机加一分,分数达到10,20,30难度增加,敌机飞出显示屏幕游戏失败)
- 穿墙透视算法|MIT华人Team通过墙壁和遮挡物的超强动作检测模型
- ibmmq 通道命令_IBM MQ通道