Java 将 int 转换为 byte 时的奇怪行为?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/842817/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 20:06:06  来源:igfitidea点击:

Odd behavior when Java converts int to byte?

java

提问by harshit

int i =132;

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

Mindboggling. Why is the output -124?

令人难以置信。为什么是输出-124

采纳答案by Wayne

In Java, an intis 32 bits. A byteis 8 bits.

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

Most primitive types in Java are signed, and byte, short, int, and longare encoded in two's complement. (The chartype is unsigned, and the concept of a sign is not applicable to boolean.)

最原始的类型Java中的签名,byteshortint,和long被编码在二进制补码。(char类型是无符号的,符号的概念不适用于boolean。)

In this number scheme the most significant bit specifies the sign of the number. If more bits are needed, the most significant bit ("MSB") is simply copied to the new MSB.

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

So if you have byte 255: 11111111and you want to represent it as an int(32 bits) you simply copy the 1 to the left 24 times.

因此,如果您有 byte 255:11111111并且您想将其表示为int(32 位),您只需将 1 向左复制 24 次。

Now, one way to read a negative two's complement number is to start with the least significant bit, move left until you find the first 1, then invert every bit afterwards. The resulting number is the positive version of that number

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

For example: 11111111goes to 00000001= -1. This is what Java will display as the value.

例如:11111111转到00000001= -1。这是 Java 将显示为值的内容。

What you probably want to do is know the unsigned value of the byte.

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

You can accomplish this with a bitmask that deletes everything but the least significant 8 bits. (0xff)

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

So:

所以:

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

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

Would print out: "Signed: -1 Unsigned: 255"

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

What's actually happening here?

这里究竟发生了什么?

We are using bitwise AND to mask all of the extraneous sign bits (the 1's to the left of the least significant 8 bits.) When an int is converted into a byte, Java chops-off the left-most 24 bits

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

1111111111111111111111111010101
&
0000000000000000000000001111111
=
0000000000000000000000001010101

Since the 32nd bit is now the sign bit instead of the 8th bit (and we set the sign bit to 0 which is positive), the original 8 bits from the byte are read by Java as a positive value.

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

回答by bdonlan

byte in Java is signed, so it has a range -2^7 to 2^7-1 - ie, -128 to 127. Since 132 is above 127, you end up wrapping around to 132-256=-124. That is, essentially 256 (2^8) is added or subtracted until it falls into range.

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

For more information, you may want to read up on two's complement.

有关更多信息,您可能需要阅读二进制补码

回答by Peter Lawrey

132 is outside the range of a byte which is -128 to 127 (Byte.MIN_VALUE to Byte.MAX_VALUE) Instead the top bit of the 8-bit value is treated as the signed which indicates it is negative in this case. So the number is 132 - 256 = -124.

132 超出了 -128 到 127(Byte.MIN_VALUE 到 Byte.MAX_VALUE)的字节范围,而是将 8 位值的最高位视为有符号的,这表示在这种情况下它是负数。所以数字是 132 - 256 = -124。

回答by Pacerier

132in digits (base 10) is 1000_0100in bits (base 2) and Java stores intin 32 bits:

132在数字(基数 10)是1000_0100在位(基数 2)和 Java 存储int在 32 位:

0000_0000_0000_0000_0000_0000_1000_0100

Algorithm for int-to-byte is left-truncate; Algorithm for System.out.printlnis two's-complement(Two's-complement is if leftmost bit is 1, interpret as negative one's-complement(invert bits) minus-one.); Thus System.out.println(int-to-byte())is:

int-to-byte 的算法是左截断的;算法 for System.out.printlnis two's -complement(Two's-complement is if most left bit is 1,解释为负的补码(反转位)减一。); 因此System.out.println(int-to-byte())是:

  • interpret-as( if-leftmost-bit-is-1[ negative(invert-bits(minus-one(] left-truncate(0000_0000_0000_0000_0000_0000_1000_0100) [)))] )
  • =interpret-as( if-leftmost-bit-is-1[ negative(invert-bits(minus-one(] 1000_0100[)))] )
  • =interpret-as(negative(invert-bits(minus-one(1000_0100))))
  • =interpret-as(negative(invert-bits(1000_0011)))
  • =interpret-as(negative(0111_1100))
  • =interpret-as(negative(124))
  • =interpret-as(-124)
  • =-124   Tada!!!
  • 解释为(if-leftmost-bit-is-1[negative(invert-bits(minus-one(] left-truncate( 0000_0000_0000_0000_0000_0000_1000_0100) [)))]]
  • = 解释为(如果最左位是 1[ 负(反转位(减一(] 1000_0100[)))] )
  • =解释为(负(反转位(减一(1000_0100))))
  • =解释为(负(反转位(1000_0011)))
  • =解释为(否定(0111_1100))
  • =解释为(否定(124))
  • =解释为(-124)
  • =-124多田!!!

回答by pen

often in books you will find the explanation of casting from int to byte as being performed by modulus division. this is not strictly correct as shown below what actually happens is the 24 most significant bits from the binary value of the int number are discarded leaving confusion if the remaining leftmost bit is set which designates the number as negative

通常在书中,您会发现从 int 转换为 byte 的解释是由模数除法执行的。这并不严格正确,如下所示,实际发生的情况是 int 数字的二进制值中的 24 个最高有效位被丢弃,如果剩余的最左边的位被设置为负数,则会留下混淆

public class castingsample{

public static void main(String args[]){

    int i;
    byte y;
    i = 1024;
    for(i = 1024; i > 0; i-- ){

      y = (byte)i;
      System.out.print(i + " mod 128 = " + i%128 + " also ");
      System.out.println(i + " cast to byte " + " = " + y);

    }

}

}

回答by typelogic

here is a very mechanical method without the distracting theories:

这是一个非常机械的方法,没有分散注意力的理论:

  1. Convert the number into binary representation (use a calculator ok?)
  2. Only copy the rightmost 8 bits (LSB) and discard the rest.
  3. From the result of step#2, if the leftmost bit is 0, then use a calculator to convert the number to decimal. This is your answer.
  4. Else (if the leftmost bit is 1) your answer is negative. Leave all rightmost zeros and the first non-zero bit unchanged. And reversed the rest, that is, replace 1's by 0's and 0's by 1's. Then use a calculator to convert to decimal and append a negative sign to indicate the value is negative.
  1. 将数字转换为二进制表示(使用计算器好吗?)
  2. 只复制最右边的 8 位 (LSB) 并丢弃其余的。
  3. 从步骤#2 的结果来看,如果最左边的位是 0,则使用计算器将数字转换为十进制。这是你的答案。
  4. 否则(如果最左边的位是 1)你的答案是否定的。保留所有最右边的零和第一个非零位不变。并将其余的颠倒过来,即用0代替1,用1代替0。然后使用计算器转换为十进制并附加一个负号表示该值为负数。

This more practical method is in accordance to the much theoretical answers above. So, those still reading those Java books saying to use modulo, this is definitely wrong since the 4 steps I outlined above is definitely not a modulo operation.

这种更实用的方法与上面的许多理论答案一致。所以,那些仍在阅读那些说要使用模的 Java 书籍的人,这绝对是错误的,因为我上面概述的 4 个步骤绝对不是模运算。

回答by bcorso

Two's complement Equation:

补码方程:

enter image description here

在此处输入图片说明



In Java, byte(N=8) and int(N=32) are represented by the 2s-complement shown above.

在 Java 中,byte(N=8) 和int(N=32) 由上面显示的 2s 补码表示。

From the equation, a7is negative for bytebut positive for int.

从等式中,a 7 对为负byte但对 为正int

coef:   a7    a6  a5  a4  a3  a2  a1  a0
Binary: 1     0   0   0   0   1   0   0
----------------------------------------------
int:    128 + 0 + 0 + 0 + 0 + 4 + 0 + 0 =  132
byte:  -128 + 0 + 0 + 0 + 0 + 4 + 0 + 0 = -124

回答by Francisco Neto

A quick algorithm that simulates the way that it work is the following:

模拟其工作方式的快速算法如下:

public int toByte(int number) {
    int tmp = number & 0xff
    return (tmp & 0x80) == 0 ? tmp : tmp - 256;
}

How this work ? Look to daixtranswer. A implementation of exact algorithm discribed in his answer is the following:

这是如何工作的?看看daixtr 的回答。他的回答中描述的精确算法的实现如下:

public static int toByte(int number) {
    int tmp = number & 0xff;
    if ((tmp & 0x80) == 0x80) {
        int bit = 1;
        int mask = 0;
        for(;;) {
            mask |= bit;
            if ((tmp & bit) == 0) {
                bit <<=1;
                continue;
            }
            int left = tmp & (~mask);
            int right = tmp & mask;
            left = ~left;
            left &= (~mask);
            tmp = left | right;
            tmp = -(tmp & 0xff);
            break;
        }
    }
    return tmp;
}

回答by devil_29

 N is input number
case 1: 0<=N<=127  answer=N;
case 2: 128<=N<=256 answer=N-256 
case 3: N>256   
        temp1=N/256;
        temp2=N-temp*256;
        if temp2<=127   then answer=temp2;
        else if temp2>=128  then answer=temp2-256;
case 4: negative  number input
        do same procedure.just change the sign of the solution           

回答by Bathsheba

Conceptually, repeated subtractions of 256 are made to your number, until it is in the range -128 to +127. So in your case, you start with 132, then end up with -124 in one step.

从概念上讲,对您的数字进行 256 的重复减法,直到它在 -128 到 +127 的范围内。因此,在您的情况下,您从 132 开始,然后一步以 -124 结束。

Computationally, this corresponds to extracting the 8 least significant bits from your original number. (And note that the most significant bit of these 8 becomes the sign bit.)

在计算上,这对应于从原始数字中提取 8 个最低有效位。(请注意,这 8 个中的最高有效位成为符号位。)

Note that in other languages this behaviour is not defined (e.g. C and C++).

请注意,在其他语言中,此行为未定义(例如 C 和 C++)。