写点什么

JAVA 中的位运算与二进制操作

  • 2022 年 4 月 25 日
  • 本文字数:2506 字

    阅读完需:约 8 分钟

负数的二进制

前面我们说了正整数的二进制运算规则,为什么不是整个整数范围的二进制运算呢?原来这个和计算机表示有关系,计算机无法读取负数,只能对应做加法,所以当一个负数转为二进制的时候,便有了新的表示法,我们称之为补码表示法

补码/反码/原码

首先我们要明白一点,二进制的首位用来表示正数还是负数,如果是 0 则是正数,1 为负数,剩下的才是对应的值,但是需要注意的一点是,计算机的计算中负数也会转换为正数来计算,而转换的过程,则是先获取绝对值(正数)得二进制结果,此过程称之为原码,然后给当前的补码每一位反过来,则是最终负数的结果,此过程称之为反码,接着通过给当前反码+1 的结果,称之为补码,****。当然由于数值类型不同,字节数不同,我们知道每一个字节占 8 个比特位,整数有四种类型,分别为 byte、short、int、long,分别占 1、2、4、8 字节,即 8、16、32、64 个比特位,所以当位数不够的时候,高位会补 0(从左到右则是高位到低位)。


例如当前值为-1,首先我们获取绝对值 1,首先是一个字节的值,也就是 8 个比特位,1 的二进制原码为 1,前面补 0,则是 00000001,接着我们将当前值反过来,得到反码 11111110,然后对反码+1 则是补码 11111111,所以-1 得值就是 11111111。


例如-127,绝对值为 127,原码为 01111111,反码为 10000000,补码则是 10000001,其他的负数都是如此。

位运算

前面介绍了整数的二进制操作,那么在计算机操作中,往往对二进制辅以位运算,以此来达到快速运算的结果,接下来,就开始学习计算机中的位运算操作,首先将所有的位运算列出来,如下:



如此多的运算,到底是如何计算的呢?


(<<)左移位


假设当前有值 int a = 5,操作为 5 << 3,则是对 5 做左移三位的操作,那么具体操作步骤是什么呢?


1.将 5 转为 32 比特位(int)的二进制,得出结果 0000 0000 0000 0000 0000 0000 0000 0101


2.这个时候将整体朝左移动三位,超过三十二位的高位舍弃(少舍弃一位,留下一位作为正负数的符号位,即正数最高位补 0,负数最高位补 1),低位不足补 0,则是 0000 0000 0000 0000 0000 0000 0010 1000 ,将当前二进制转换为十进制,则是 40,所以最终计算的结果为 40


public class LeftMoving{public static void main(String[] args){int a = 5;System.out.println("5<<3="+(a << 3));//5<<3=40}}


(>>)右移位


假设当前值 int a = 5,操作为 5>>1,则是对 5 右移 1 位的操作,具体步骤如下:


1.将 5 转为 32 比特位的二进制,结果为 0000 0000 0000 0000 0000 0000 0000 0101


2.将整体二进制的结果右移 1 位,如果本身为正数,首个最高位补 0,负数首个最高位补 1,其他高位补 0,超过的低位舍弃,结果为 00000 0000 0000 0000 0000 0000 0000 010,将这个值转为十进制为 2,所以最终结果为 2


public class NegativeRightMoving{public static void main(String[] args){int a = 5;System.out.println("5>>1="+(a>>1));//5>>1=2}}


(>>>)无符号右移


这里我们假设值 int a = -5,操作为-5>>>1,操作如下:


1.原码为 0000 0000 0000 0000 0000 0000 0000 0101


2.反码为 1111 1111 1111 1111 1111 1111 1111 1010


3.补码为 1111 1111 1111 1111 1111 1111 1111 1011


4.整体右移 1 位,高位补 0,低位超过部分舍弃,则为 0111 1111 1111 1111 1111 1111 1111 1101,转为十进制为 2147483645 ,所以最终结果为 2147483645


public class UnsignedRightMoving{public static void main(String[] args){int a = -5;System.out.println("-5>>>1="+(a>>>1));//-5>>>1=2147483645}}


ps:一定要分清楚无符号右移和右移操作的区别,右移位运算符>>,若操作的值为正,则在高位插入 0;若值为负,则在高位插入 1,右移补零操作符>>>,无论正负,都在高位插入 0


(&)位与运算符


假设值 int a = 129,操作为 129&128,具体步骤如下:


1.129 转为二进制 0000 0000 0000 0000 0000 0000 1000 0001,128 转二进制为 0000 0000 0000 0000 0000 0000 1000 0000


2.从最高位开始比较,同一位的两个值都为 1 则是 1,否则为 0,则最终结果为 0000 0000 0000 0000 0000 0000 1000 0000 ,即 128


public static void main(String[] args){System.out.println("129&128="+(129&128));//129&128=128}


(|)位或运算符


假设值 int a = 129,操作为 129|128,具体步骤如下:


1.129 转为二进制 0000 0000 0000 0000 0000 0000 1000 0001,128 转二进制为 0000 0000 0000 0000 0000 0000 1000 0000


2.从最高位开始比较,同一位的两个值有一个为 1 则是 1,否则为 0,则最终结果为 0000 0000 0000 0000 0000 0000 1000 《一线大厂 Java 面试题解析+后端开发学习笔记+最新架构讲解视频+实战项目源码讲义》无偿开源 威信搜索公众号【编程进阶路】 0001 即 129


public static void main(String[] args){System.out.println("129|128="+(129|128));//129|128=129}


(~)位非运算符


假设值为 37,操作为~37,具体步骤如下:


1.37 转为二进制为 00000000 00000000 00000000 00100101


2.~操作是指如果每一位的值为 0,则是 1,如果为 1,则是 0,所以整体取反,结果为 11111111 11111111 11111111 11011010


3.由于当前获取的结果首位为 1,代表值为负数,那么我们通过当前补码计算原码,首先将补码-1 得到反码,则为 11111111 11111111 11111111 11011001,然后整体取反,则为 00000000 00000000 00000000 00100110 ,转为 10 进制为 38,由于是负数,则最终结果为-38


public static void main(String[] args){System.out.println("~37="+(~37));//~37=-38}


(^)位异或运算


假设当前值为 8,操作为 8^11,具体操作如下:


1.8 转为二进制 0000 0000 0000 0000 0000 0000 0000 1000 ,11 转为二进制为 0000 0000 0000 0000 0000 0000 0000 1011


2.^运算符则是比较每一位的值是否一致,一致为 0,否则为 1,所以比较的结果为 0000 0000 0000 0000 0000 0000 0000 0011 ,转为十进制结果为 3


public static void main(String[] args){System.out.println("8^11="+(8^11));//8^11=3}


(<<=)左移赋值


假设当前有值 int a = 5,操作为 a <<= 3,那么具体操作步骤是什么呢?


1.先将 5 做左移三位的操作,得出结果为 40(此步骤与<<一致)


2.然后将最终结果重新赋值给 a,即 a 为 40


public class LeftMoving{public static void main(String[] args){int a = 5;a <<= 3;//a = a << 3System.out.println(a);//40}

用户头像

还未添加个人签名 2022.04.13 加入

还未添加个人简介

评论

发布
暂无评论
JAVA中的位运算与二进制操作_Java_爱好编程进阶_InfoQ写作社区