问题

int i =132;
byte b =(byte)i;
System.out.println(b);

输出为-124

这是为什么?我知道这是一个非常基本的问题,但我仍然无法对其进行映射,或者了解这是如何发生的?


#1 热门回答(154 赞)

在Java中,anint是32位。 Abyteis 8bits

Java中的所有内容都已签名,bytes,ints,longs以二进制编码进行编码。

在此numbercheme中,最重要的位指定数字的符号。如果需要更多位,则将最高有效位("MSB")简单地复制到新MSB。

因此,如果你有byte25511111111并且你想将其表示为int(32位),则只需将1复制到左侧24次。

现在,读取负二进制补码的一种方法是从最低有效位开始,向左移动直到找到第一个1,然后反转每一位。结果数字是该数字的正数

例如:11111111goes to00000001 = -1。这就是Java将显示为值的内容。

你可能想要做的是知道字节的无符号值。

你可以使用位掩码来完成此操作,该位掩码删除除最低8位之外的所有内容。 (0xff的)

所以:

byte signedByte = -1;
int unsignedByte = signedByte & (0xff);

System.out.println("Signed: " + signedByte + " Unsigned: " + unsignedByte);

打印出来:"Signed: -1 Unsigned: 255"

这里到底发生了什么?

我们使用按位AND来屏蔽所有无关的符号位(最低有效8位左侧的1)。当int转换为字节时,Java会截断最左边的24位

1111111111111111111111111010101
&
0000000000000000000000001111111
=
0000000000000000000000001010101

由于第32位现在是符号位而不是第8位(我们将符号位设置为0,这是正数),因此字节的原始8位由Java读取为正值。


#2 热门回答(78 赞)

要了解它是如何工作的,我们需要知道计算机是按位工作的。

132 inbase 10(十进制)is10000100inbase 2(二进制)。由于Java以32位存储int,我们拥有的是

00000000_00000000_00000000_10000100

当aint转换为abyte时,Javachops-off最左边的24位。我们得到的是10000100

two's complement中,最左边的位用作符号。如果最左边的位是0,则不会再进行任何操作。

如果最左边的位是1(正如我们在这里),则表示该数字为负数,需要完成更多工作。为了得到幅度,我们减去1然后applyone's complement(应用一个补码意味着我们反转位):

  • 10000100 - 1 = 10000011
  • 反转10000011 = 01111100

01111100当被解释为十进制数时,是124。

所以我们有一个124的负数,给我们**-124**。


#3 热门回答(22 赞)

Java中的字节是有符号的,所以它的范围是-2 ^ 7到2 ^ 7-1 - 即-128到127.由于132高于127,你最终会回绕到132-256 = -124。也就是说,基本上加上或减去256(2 ^ 8)直到它落入范围。

有关更多信息,你可能需要阅读two's complement


原文链接