下面这行代码会输出什么?
byte b = -1;
System.out.println(b & 0xff);
一个byte占8位,再和8位都为1的0xff与操作,那么结果应该是它本身才对,可是运行上面的代码输出却是255。 要想读懂上面的代码,首先我们要弄清楚以下几个问题。
在Java中数值类型的首位(bit)表示符号位,0表示正数,1表示负数。但是需要注意的是,由于Java采用”2的补码“(Two's Complement)编码负数,所以如果把负数的首位改成0,修改后的值和其绝对值并不相等,所以处理负数时要格外小心。
Java语言规范2中明确指出位操作符(Bitwise Operators)只作用于integer类型(其实也可以作用于long类型)。所以如果操作数是byte/short类型,则在位操作之前会被转换成integer类型。详情请参考Java 语言规范 5.6.2. Binary Numeric Promotion。
0xff返回的是32位integer类型。在Java中integer类型(例如1)有三种表示方式:十进制(1)、八进制(01)和十六进制(0x01)。
在Java中窄类型向宽类型转换时需要进行符号位扩展,如果该byte是负数则左边要补齐相应个数1,如果是正数则要补齐相应个数0.
我们再回头看上面的代码:
b & 0xff
在&操作之前,b被转换成integer类型,左边用符号位1补齐:
11111111 11111111 11111111 11111111
0xff是integer字面量,二进制值为:
00000000 00000000 00000000 11111111
执行&操作,结果为:
00000000 00000000 00000000 11111111
返回结果是integer类型,符号位是0,所以是一个正数,值为255。
下面是一个更复杂的例子,功能是将长度为4的byte数组转换成integer类型:
public class BytesArrayToInt {
public static void main(String[] args) {
System.out.println(byteArrayToInt(new byte[]{0x01, 0x01, 0x01, 0x01}));
}
public static int byteArrayToInt(byte[] b) {
if (b.length == 4) {
return b[0] << 24 | (b[1] & 0xff) << 16 | (b[2] & 0xff) << 8 | (b[3] & 0xff);
} else {
throw new InvalidParameterException("The bytes array length must be 4.");
}
}
}