带符号字节的按位与运算

Bitwise AND operation with a signed byte

代码如下:

int i = 200;
byte b = (byte) 200;
System.out.println(b);
System.out.println((short) (b));
System.out.println((b & 0xff));
System.out.println((short) (b & 0xff));

这是输出:

-56
-56
200
200

按位与 0xff 不应该改变 b 中的任何内容,但显然它确实有效果,为什么?

Java byte 是有符号类型。这就是为什么您在打印时会看到一个负数:200 或 0xC8 高于 byte 表示的最大正数,因此它被解释为负数 byte

然而,0xff 常量是一个 int。当您对 byteint* 执行算术和按位逻辑运算时,结果变为 int。这就是为什么您在第二组示例中看到 200 的原因:(b & 0xff) 生成一个整数 200,它在收缩转换为 short 后仍然是 200,因为200 适合 short 而不会变为负值。

* 或另一个 byte,就此而言; Java 标准指定了根据操作数类型应用的转换列表。

它有影响,因为 200 超出了最大可能(有符号)byte127。由于此溢出,该值已分配 -56。值 -128 的最高有效字节已设置。

11001000

因此,前 2 个输出语句显示 -56,并且强制转换为 short 将执行符号扩展以保留负值。

当您执行 & 0xff 时,会发生 2 件事。首先,该值被提升为带有符号扩展的 int

11111111 11111111 11111111 11001000

然后进行位与运算,只保留最后8位。这里第8位不再是-128,而是128,所以恢复了200

00000000 00000000 00000000 11001000

无论是否将值强制转换为 short,都会发生这种情况; a short 有 16 位,可以很容易地表示 200.

00000000 11001000

使用不同的整数类型是一个雷区。

例如,这里发生了什么?

byte b = (byte) 200;

实际上相当于

int i = 200;
byte b = (byte)i;

并且缩小转换 (byte) 只是取 int 值的最低 8 位。