最近有涉及的网络编程方面的工作,对java的位操作算是入门了!
/**
* The default byte order of bytes: BIG_ENDIAN
*
* @param bytes
* @return
*/
public static final int getUnsignedInt(byte... bytes) {
switch (bytes.length) {
case 1:
return 0xFF & bytes[0];
case 2:
return ((0xFF & bytes[0]) << 8) | (0xFF & bytes[1]);
case 3:
return ((0xFF & bytes[0]) << 16) | ((0xFF & bytes[1]) << 8) | (0xFF & bytes[2]);
case 4: {
int i = ((0xFF & bytes[0]) << 24) | ((0xFF & bytes[1]) << 16) | ((0xFF & bytes[2]) << 8)
| (0xFF & bytes[3]);
if (i > 0)
return i;
}
}
throw new RuntimeException("over the max value");
}
以上代码,隐藏了如下知识点:
1. java中,使用补码的形式来表示二进制的:
a). 正数的原码、反码和补码是一样的;
b). 负数的补码有如下规则:原码——>反码——>补码
原码:负数的原码为1|x|
反码:负数的反码,符号位不变,数值取反
补码:负数的反码加1(会影响符号位)
2. java中进行算术和位运算时
a). 整数存储时,使用的是big-endian字节序列: 高字节在前,低字节在后
b). 类型会自动按精度从“低”到“高”进行转换,转换的顺序如下:
byte——>short——>int——>long——>float——>double
c). 位运算后,byte,short都转换了int类型
// 值为2,这里赋值的就是用的补码形式
int i2 =0x02;
// 值为-2,这里赋值的就是用的补码形式
int i_2 = 0xFFFFFFFE;
byte b1 = (byte) 0x01;
byte b_1 = (byte) 0xFF;
byte b_2 = (byte) 0xFe;
System.out.println("b_1: " + b_1);
System.out.println("0x0FF & b_1: " + (0x0FF & b_1));
// -2的补码进行左移后,得到是-256。由于负数补码与原码不一样,因此左移操作后,高位也会发生了变化,再转换成原码计算出的数值就不是预期的 。
System.out.println("b_1 << 8: " + (b_1 << 8));
// 终于明白0xFF&的作用了:使用0xFF&是为了确保负整数的高位不变,即为0x000000FF&
System.out.println("(0xFF & b_1) << 8: " + ((0xFF & b_1) << 8));
// 但如果操作是正数,则不用0xFF来保证高位不变,是因为正数的补码与原码是一样的,左移操作后,除了低位左移了指定位数外,补码其它高位并没有变化(即都是0)
System.out.println("b1 << 8 : " + (b1 << 8));
// 把-1这个数值强制转换成了int型
int i_1 = b_1;
System.out.println(i_1 << 8);