ThinkChat🤖让你学习和工作更高效,注册即送10W Token,即刻开启你的AI之旅 广告
[TOC] > 1. Java移位运算符不外乎就这三种:<<(左移)、>>(带符号右移)和>>>(无符号右移) > 2. java中的移位操作仅仅对int和long有效,byte、short、char升级为int后再进行移位 > 3. 计算机中存的都是补码,整数的原码、反码、补码都一样,负数的 补码是,符号位不变,取反(反码)+1 ### 1. 左移运算符 > 左移运算符<<使指定值的所有位都左移规定的次数。 1)它的通用格式如下所示: ~~~ value << num ~~~ > num 指定要移位值value 移动的位数。 > 左移的规则只记住一点:丢弃最高位(符号位同样丢弃),0补最低位 2)运算规则 > 1. 按二进制形式把所有的数字向左移动对应的位数,高位移出(舍弃),低位的空位补零。 > 2. 当左移的运算数是int 类型时,每移动1位它的第31位就要被移出并且丢弃; > 3. 当左移的运算数是long 类型时,每移动1位它的第63位就要被移出并且丢弃。 > 4. 当左移的运算数是byte 和short类型时,将自动把这些类型扩大为 int 型。 3)数学意义 > 在数字没有溢出的前提下,对于正数和负数,左移一位都相当于乘以2的1次方,左移n位就相当于乘以2的n次方 4)计算过程: 例如:3 <<2(3为int型) > 1)把3转换为二进制数字0000 0000 0000 0000 0000 0000 0000 0011, > 2)把该数字高位(左侧)的两个零移出,其他的数字都朝左平移2位 > 3)在低位(右侧)的两个空位补零。则得到的最终结果是0000 0000 0000 0000 0000 0000 0000 1100, > 转换为十进制是12。 ### 2. 右移运算符 > 右移运算符<<使指定值的所有位都右移规定的次数。 1)它的通用格式如下所示: ~~~ value >> num ~~~ > num 指定要移位值value 移动的位数。 > 右移的规则只记住一点:符号位不变,左边补上符号位 2)运算规则: > 1. 按二进制形式把所有的数字向右移动对应的位数,低位移出(舍弃),高位的空位补符号位,即正数补零,负数补1 > 2. 当右移的运算数是byte 和short类型时,将自动把这些类型扩大为 int 型。 > 3. 例如,如果要移走的值为负数,每一次右移都在左边补1,如果要移走的值为正数,每一次右移都在左边补0,这叫做符号位扩展(保留符号位)(sign extension ),在进行右移操作时用来保持负数的符号。 3)数学意义 > 右移一位相当于除2,右移n位相当于除以2的n次方。 4)计算过程 11 >>2(11为int型) > 1)11的二进制形式为:0000 0000 0000 0000 0000 0000 0000 1011 > 2)把低位的最后两个数字移出,因为该数字是正数,所以在高位补零。 > 3)最终结果是0000 0000 0000 0000 0000 0000 0000 0010。 转换为十进制是3。 35 >> 2(35为int型) 35转换为二进制:0000 0000 0000 0000 0000 0000 0010 0011 把低位的最后两个数字移出:0000 0000 0000 0000 0000 0000 0000 1000 转换为十进制: 8 ### 3. 无符号右移 > 无符号右移运算符>>> 它的通用格式如下所示: ~~~ value >>> num ~~~ > 1. num 指定要移位值value 移动的位数。 > 2. 无符号右移的规则只记住一点:忽略了符号位扩展,0补最高位 ### 4. 运算 #### 4.1 &(按位与) > * 两位全位1,结果才为1; `0&0=0; 0&1=0 ; 1&1=1` 如:`51 &5 =0011 0011 & 0000 0101=0000 0001 = 1` 作用:清零、取一个数中指定位(即被与数0000) #### 4.2 | (按位或) > * 只要一个为1,结果就为1 #### 4.3 ^(异或) 相同为0,不相同为1 `0 ^ 0 =0 ; 0 ^1 = 1 ; 1 ^ 1=0;` #### 4.4 ~(按位取反) 按位取反, 0变成1 ,1变成 0; #### 5. int与byte转换 ~~~ public static byte[] intToByte(int a){ byte bt[]=new byte[4]; bt[0]=(byte)((a>>0*8)&0xff); bt[1]=(byte)((a>>1*8)&0xff); bt[2]=(byte)((a>>2*8)&0xff); bt[3]=(byte)((a>>3*8)&0xff); return bt; } public static int byteToInt(byte[] a){ System.out.println((int)a[0]); //这里输出的是-49 System.out.println((int)(a[0]&0xff));//这里输出是207 int rs0=(int)((a[0]&0xff)<<0*8); int rs1=(int)((a[1]&0xff)<<1*8); int rs2=(int)((a[2]&0xff)<<2*8); int rs3=(int)((a[3]&0xff)<<3*8); int result=rs0+rs1+rs2+rs3; return result; } ~~~ &0xff 是16进制,二进制表示为11111111 * 因为对byte进行操作,所以或升级为int,负数高位全补1,所以会对结果产生错误影响,但是加了&0xff,高位变为0,成为正确结果 发现一个奇怪的现象, 直接输出(int)a[0]结果是-49,而(int)(a[0]&0xff)理论上不变,但是输出的结果却是207; 原来,Java的int是4个字节32位的,在控制台进行输出的时候,jvm把11001111之前进行了补全,补为11111111 11111111 11111111 11001111,显然这是-49的补码,输出结果是-49;而如果进行了a[0]&0xff ,补全后则变成00000000 00000000 00000000 11001111,此时结果变成了207,这时进行运算结果才是正确的。 java中,转换时int输出时 若byte符号位是0,如01001000,则进行int补0处理--》00000000 00000000 00000000 01001000; 若byte符号位是1,如11001000,则进行补1处理-->1111111 11111111 11111111 11001000 Ps: &0xff的作用就是把其他位置0,这八位不变; 一些实用的函数:Integer.toBinaryString(8100);可以输出二进制码; String s="abc"; byte[] bt = s.getBytes();可以得到字符串的二进制码// s.getByte("utf-8")参数也可以指定编码方式! for(byte b:bt){ System.out.println(Integer.toBinaryString(b));//输出二进制码 } 如果通过字节序列变成string,可以通过String s=new String(bt,"asci"); 形式 ## 5. 字节操作 ~~~ public static byte setBitValue(byte source, int pos, byte value) { byte mask = (byte) (1 << pos); if (value > 0) { source |= mask; } else { source &= (~mask); } return source; } ~~~ value>0 例如:设置第二位为1(source,2,1) (byte) (1 << pos); 00000001 -》00000100 | 与 00001000 得到 00001100 source &= (~mask); 00000100 -》01111011 & 00001000 其他为不变 00001000