今天看到一段代码,有个比较经典的错误。一般喜欢搞协议编解码或自己实现持久化的童鞋应该都会碰到。
[code]
public static long toLong(byte... b) {
long l = 0;
int len = b.length;
if (len > 0) l = b[0];
if (len > 1) l = ((long) l << 8 | b[1]);
if (len > 2) l = ((long) l << 16 | b[2]);
if (len > 3) l = ((long) l << 24 | b[3]);
if (len > 4) l = ((long) l << 32 | b[4]);
if (len > 5) l = ((long) l << 40 | b[5]);
if (len > 6) l = ((long) l << 48 | b[6]);
if (len > 7) l = ((long) l << 56 | b[7]);
return l;
}
[/code]

这一块代码有两个问题:
1、byte是有符号数。这个用法看起来是当符号来操作的。比如:byte[0]为0x80,在byte表示的有符号数里是-128,实际上应该是128。
2、byte做位运算,另一个操作数是long时会自动扩展符号位到long,另一操作数是byte或int时,会自动扩展符号位到int。以下举例说明
如果byte最高位即符号位为1,即0x80到0xff之间,与int或byte类型值做位运算时,会先把符号位外扩(或者说是补足位数)成0xffffff80到0xffffffff,结果就会跟预期的不一样。

这两个问题的处理方法都很简单,把byte跟0xff做&运算后,再跟别的做操作,就没问题。
比如:0x80跟0xff做&运算时,0x80会自动扩充为0xffffff80,0xff本身是int,即0x000000ff,所以&到的结果是0x00000080,就是128,这个才是期望的值。

改起来也很容易,简单改造
[code]
public static long toLong2(byte... b) {
long l = 0;
int len = b.length;
if (len > 0) l = b[0] & 0xff;
if (len > 1) l = ((long) l << 8 | (b[1] & 0xff));
if (len > 2) l = ((long) l << 16 | (b[2] & 0xff));
if (len > 3) l = ((long) l << 24 | (b[3] & 0xff));
if (len > 4) l = ((long) l << 32 | (b[4] & 0xff));
if (len > 5) l = ((long) l << 40 | (b[5] & 0xff));
if (len > 6) l = ((long) l << 48 | (b[6] & 0xff));
if (len > 7) l = ((long) l << 56 | (b[7] & 0xff));
return l;
}
[/code]

标签: byte, Java, 位运算, 符号位

添加新评论