为什么按位与 0xFF 的负符号整数会产生正符号整数?

Why negative signed integer with bitwise AND 0xFF will result in positive signed integer?

我的目标是理解二进制补码。

10000111 有符号整数等于 -121。但是,如果您将它与十六进制的 0xFF 或十进制的 11111111 按位 AND,它将等于 135.

在我看来,这不应该发生,因为最高字节 10000111 与结果字节 10000111

相同
    10000111
AND 11111111
------------
    10000111 = 135.

我的预期结果是值不应更改,等于 -121

我的实际结果是数值变化。

我的猜测是,0xFFunsigned bit。因此,最高字节的 signed1 和较低字节的 unsigned1 将导致 unsigned位1。但是……那是不对的。

@TestInstance(TestInstance.Lifecycle.PER_CLASS)
class WebSocketWorkerThreadTest {
  @Test
  void SignedToUnsignedInteger() {
    byte signed = (byte) 0b10000111;
    // If java uses unsigned integer, it should be 135. however, java uses signed integer. Therefore, the outputs will be -121
    // 10000111
    // ^
    // the sign bit. If it exists then the value will be negative.
    Assertions.assertEquals(-121, signed);
    // 10000111
    // 11111111
    // --------
    // 10000111
    int unsigned = signed & 0xFF;
    Assertions.assertEquals(135, unsigned);
  }
}

Java 以二进制补码形式存储整数(long 和 byte)。参见 https://en.wikipedia.org/wiki/Two%27s_complement

在这种表示中,任何负数都以一串 1 位开头,因为值 10000... 0000 是最低可表示值,而值 1111... 111 是 -1。 出于这个原因,当您剪切前导 1 位时,您将数字完全向上移动到正数范围内,因为新数字不再以 1 位开头。

在你的例子中,你使用了字节,但你的字节值没有你期望的形式。它是一个整数,当应用 & 操作时,因为您没有将 0xFF 转换为字节。解决此问题的最简单方法是将 & 操作的结果转换为字节,如另一个答案所建议的那样。

当您应用 & 运算符时,

signed 被提升为 int,因为 二进制数字提升 .

不是10000111 & 11111111,是11111111111111111111111110000111 & 00000000000000000000000011111111,它的值是00000000000000000000000010000111(还是一个int)。

此处的 MSB 为零,因此为正数。

如果你将它转换回一个字节,这将只占用 8 个 LSB,该字节将再次为负。