字节位移
位移是在一个字节二进制(只能是0和1)的基础上进行位的移动操作,一个字节有8位组成,理论上位移后空出的位由0不足。比如11111111,往左移1位(<<1)就应该是11111110,往右移一位(>>1)为011111111.
实践
都是在以下字节的前提下进行操作
byte[] b = new byte[2];
b[0] = (byte) 0xff;//255
System.out.println(Integer.parseInt(Integer.toBinaryString(b[0]&0xff), 2));
System.out.println(b[0]);//java 中有符号的-1
System.out.println(Integer.toBinaryString(b[0]&0xff));//输出二进制字符串,按位与只输出8位一个字节
输出
255
-1
11111111
左移2位,期望11111100;
b[0] = (byte) (b[0] << 2);
System.out.println(Integer.parseInt(Integer.toBinaryString(b[0]&0xff), 2));
System.out.println(b[0]);//java 中有符号的-4
System.out.println(Integer.toBinaryString(b[0]&0xff));//输出二进制字符串,按位与只输出8位一个字节
结果
252
-4
11111100
可以看到与我们期望的结果一致
右移2位期望得到00111111
b[0] = (byte) (b[0] >> 2);
System.out.println(Integer.parseInt(Integer.toBinaryString(b[0]&0xff), 2));
System.out.println(b[0]);
System.out.println(Integer.toBinaryString(b[0]&0xff));//输出二进制字符串,按位与只输出8位一个字节
结果
255
-1
11111111
可以看到,并不是我们原先期望的结果,不是由0填充的,而是由1填充的,这是为什么呢?
Java中byte有4位,范围从-128到127,即从11111111到01111111,二进制中最高的一个位只是标志位,并不进行运算,0代表正数,1代表负数。在进行位移时,byte先转成int类型,我们知道,int由32个位组成,在byte转成int 中,不足的位如果是正数则有0填充,负数则有1填充。所以-1其实是在位移时是都是由1对空出的位进行填补,左移不受影响,右移正数不受影响。
正确的操作
取低8位进行位移
b[0] = (byte) ((b[0]&0xff) >> 2);
从字节码来看byte的位移
57: aload_1
58: iconst_0
59: aload_1 //从局部变量1中装载引用类型值入栈。
60: iconst_0 //0(int)值入栈。
61: baload //从boolean类型数组或byte类型数组中装载指定项的值(先转换为int类型值,后压栈)。
62: sipush 255 //(valuebyte1 << 8) | valuebyte2 值带符号扩展成int值入栈。
65: iand //对int类型按位与运算。
66: iconst_2 //2(int)值入栈。
67: ishr //算术右移int类型值。
68: i2b //将栈顶int类型值截断成byte类型,后带符号扩展成int类型值入栈。
69: bastore