添加后出现意外结果



我现在正在用Java编写一个个人项目,最近第一次使用位操作。我试图将两个字节转换为一个短字节,一个字节是高 8 位,另一个是下 8 位。

我在运行下面的第一行代码时遇到了错误。

不正确的结果

short regPair = (short) ( (byte1 << 8) + (byte2) );

正确的结果

short regPair = (short) ( (byte1 << 8) + (byte2 & 0xFF) );

预期结果是:AAAAAAAABBBBBBBB,其中A表示来自byte1的位,B表示来自byte2的位。

使用第一行代码,我将在位移字节 1 和添加字节 2 之间得到典型的加法。

错误结果示例

byte1 = 11, byte2 = -72
result = 2816 -72
       = 2744

当使用产生预期结果的代码行时,我可以得到 3000 的正确答案。我很好奇为什么byte2需要位屏蔽.我的想法是,它在加法之前将byte2转换为二进制,然后对两个字节执行二进制加法。

在不正确的情况下,由于+运算符,byte2被提升为int。这不仅仅意味着在byte2二进制表示的开头添加一些零。由于整数类型在 Java 中以 2 的补码表示,因此将添加 1。促销后,byte2变为:

1111 1111 1111 1111 1111 1111 1011 1000

通过执行& 0xFF,您强制提升首先int,然后保留最低有效 8 位:1011 1000并将其他所有内容设为 0。

直接打印中间值以查看发生了什么。喜欢

System.out.printf("%d %s%n", ((byte) -72) & 0xFF, Integer.toBinaryString(((byte) -72) & 0xFF));

我得到

184 10111000

所以正确的代码实际上是加 184(而不是减去 72)。

所以我完全忘记了byte是用 Java 唱的,因此当使用这种数据类型的变量执行数学运算时,它将采用有符号解释而不是位的直接值。通过执行byte2 & 0xFF,Java将有符号字节值转换为无符号整数,除了前8位之外的所有位都设置为0。因此,您可以正确执行二进制加法。

有符号字节值0x11111111 = -1

无符号字节值0x11111111 = 255

在这两种情况下,当 它被评估。

byte byte1 = 11, byte2 = -72;
short regPair = (short) ( (byte1 << 8) + (byte2) );

(2816) + (-72) = 2744

即使在下面的表达式中,字节也被提升为 int

short regPair = (short) ( (byte1 << 8) + (byte2 & 0xFF) );

2816 + 184 = 3000

在这个表达式中,没有像上面问题中表达的那样的两个字节的串联 - AAAAAAABBBBB,其中 A 表示来自字节 1 的位,B 表示来自字节 2 的位。

实际上 -7 和 255 给出 184,将其添加到 2816 中得到输出 3000。

最新更新