byte与0xff运算

160 阅读2分钟

左移

  1. m<<n:把整数m表示的二进制数左移n位,高位移出n位都舍弃,低位补0
  2. m<<n即在数字没有溢出的前提下,对于正数和负数,左移n位都相当于m乘以2的n次方
  3. 运算方式:数值的补码全部往左移动X位,符号位和最高位都舍弃,最低位补0 负数: 
    int a = -5 ; 
    int b = a << 2 ; 
    [ 1000 0000 0000 0000 0000 0000 0000 0101 ] -5的原码 
    [ 1111 1111 1111 1111 1111 1111 1111 1010 ] -5的反码 
    [ 1111 1111 1111 1111 1111 1111 1111 1011 ] -5的补码 
    [ 1111 1111 1111 1111 1111 1111 1110 1100 ] a<<2左移2位 
    将补码转换成原码就可以得到数值,补码转原码和原码转补码一样。 
    [ 1000 0000 0000 0000 0000 0000 0001 0011 ] 
    [ 1000 0000 0000 0000 0000 0000 0001 0100 ] 得到a<<2的原码,即 -20 
    左移n位就相当于乘以2的n次方

右移

  1. m>>n的含义:把整数m表示的二进制数右移n位,m为正数,高位全部补0;m为负数,高位全部补1
  2. m>>n即m除以2的n次方,得到的为整数时,即为结果。如果结果为小数,此时会出现两种情况: 如果m为正数,得到的商会无条件 的舍弃小数位; 如果m为负数,舍弃小数部分,然后把整数部分加+1得到位移后的值
  3. 运算方式:数值的补码向右移X位,符号位不变(左边补上符号位) 负数: 
    int a = -8 ; 
    int b = a >> 1 ; 
    [ 1000 0000 0000 0000 0000 0000 0000 1000 ] -8的原码 
    [ 1111 1111 1111 1111 1111 1111 1111 0111 ] -8的反码 
    [ 1111 1111 1111 1111 1111 1111 1111 1000 ] -8的补码 
    [ 1111 1111 1111 1111 1111 1111 1111 1100 ]  a>>1向右移1位 
    补码转原码 
    [ 1000 0000 0000 0000 0000 0000 0000 0011 ] 
    [ 1000 0000 0000 0000 0000 0000 0000 0100 ]   得到a>>1的原码,即 -4
/** 
  将一个int数字转换为二进制的字符串形式。`
* @param num 需要转换的int类型数据`
* @param digits 要转换的二进制位数,位数不足则在前面补0`
* @return 二进制的字符串形式`
*/
public static String toBinary(int num, int digits) {
    String cover = Integer.toBinaryString(1 << digits).substring(1);
    String s = Integer.toBinaryString(num);
    return` `s.length() < digits ? cover.substring(s.length()) + s : s;
}

示例

public class Test {
    public static void main(String[] args) {
        byte[] a = new byte[10];
        a[0]= -127;
        System.out.println(a[0]);
        int c = a[0]&0xff;
        System.out.println(c);
    }
}

结果:
-127
129

  1. 当将-127赋值给a[0]时候,a[0]作为一个byte类型,计算机存储的补码是10000001(8位)。
  2. 将a[0] 作为int类型向控制台输出的时候,jvm作了一个补位的处理,因为int类型是32位所以补位后的补码就是1111111111111111111111111 10000001(32位),这个32位二进制补码表示的也是-127.
  3. 为什么byte类型的数字要&0xff再赋值给int类型?
    其本质原因就是想保持二进制补码的一致性,当byte要转化为int的时候,高的24位必然会补1,其二进制补码其实已经不一致,&0xff可以将高的24位置为0,低8位保持原样。这样做的目的就是为了保证二进制数据的一致性,保证了二进制数据性的同时,如果二进制被当作byte和int来解读,其10进制的值必然是不同的,因为符号位位置已经发生了变化.
   int c = a[0]&0xff;  
   a[0]&0xff=111111111111111111111111110000001&11111111=000000000000000000000000 10000001 
  • 这个值算一下就是129,为什么上面的式子中a[0]不是8位而是32位,因为当系统检测到byte可能会转化成int或者说byte与int类型进行运算的时候,就会将byte的内存空间高位补1(也就是按符号位补位)扩充到32位,再参与运算。0xff其实是int类型的字面量值
/**
     * int转byte[]
     * 该方法将一个int类型的数据转换为byte[]形式,因为int为32bit,而byte为8bit所以在进行类型转换时,知会获取低8位,
     * 丢弃高24位。通过位移的方式,将32bit的数据转换成4个8bit的数据。注意 &0xff,在这当中,&0xff简单理解为一把剪刀,
     * 将想要获取的8位数据截取出来。
     * @param i 一个int数字
     * @return byte[]
     */
    public static byte[] int2ByteArray(int i){
        byte[] result=new byte[4];
        result[0]=(byte)((i >> 24)& 0xFF);
        result[1]=(byte)((i >> 16)& 0xFF);
        result[2]=(byte)((i >> 8)& 0xFF);
        result[3]=(byte)(i & 0xFF);
        return result;
    }
    /**
     * byte[]转int
     * 利用int2ByteArray方法,将一个int转为byte[],但在解析时,需要将数据还原。同样使用移位的方式,将适当的位数进行还原,
     * 0xFF为16进制的数据,所以在其后每加上一位,就相当于二进制加上4位。同时,使用|=号拼接数据,将其还原成最终的int数据
     * @param bytes byte类型数组
     * @return int数字
     */
    public static int bytes2Int(byte[] bytes){
        int num=bytes[3] & 0xFF;
        num |=((bytes[2] <<8)& 0xFF00);
        num |=((bytes[1] <<16)& 0xFF0000);
        num |=((bytes[0] <<24)& 0xFF0000);
        return num;
    }