简体   繁体   English

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

[英]Odd behavior when Java converts int to byte?

int i =132;

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

Mindboggling.令人难以置信。 Why is the output -124 ?为什么输出-124

In Java, an int is 32 bits.在 Java 中, int是 32 位。 A byte is 8 bits .一个byte是 8 bits

Most primitive types in Java are signed, and byte , short , int , and long are encoded in two's complement. Java 中的大多数原始类型都是有符号的,并且byteshortintlong以二进制补码进行编码。 (The char type is unsigned, and the concept of a sign is not applicable to boolean .) 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 : 11111111 and you want to represent it as an int (32 bits) you simply copy the 1 to the left 24 times.因此,如果您有字节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.现在,读取负二进制补码的一种方法是从最低有效位开始,向左移动直到找到第一个 1,然后反转每一位。 The resulting number is the positive version of that number结果数字是该数字的正数

For example: 11111111 goes to 00000001 = -1 .例如: 11111111转到00000001 = -1 This is what Java will display as the value.这是 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.您可以使用位掩码来完成此操作,该位掩码会删除除最低有效 8 位之外的所有内容。 (0xff) (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 位读取为正值。

132 in digits ( base 10 ) is 1000_0100 in bits ( base 2 ) and Java stores int in 32 bits: 132位(基数 10 )是1000_0100位(基数 2 ),Java 以 32 位存储int

0000_0000_0000_0000_0000_0000_1000_0100

Algorithm for int-to-byte is left-truncate; int-to-byte 的算法是左截断的; Algorithm for System.out.println is two's-complement (Two's-complement is if leftmost bit is 1 , interpret as negative one's-complement (invert bits) minus-one.); System.out.println算法是二进制补码(二进制补码是如果最左边的位是1 ,则解释为负的补码(反转位)减一。); Thus System.out.println(int-to-byte( )) is:因此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 ) [)))] )解释为(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 [)))] ) = 解释为(如果最左位是 1[ 负(反转位(减一(] 1000_0100 [)))] )
  • =interpret-as(negative(invert-bits(minus-one( 1000_0100 )))) =解释为(负(反转位(减一( 1000_0100 ))))
  • =interpret-as(negative(invert-bits( 1000_0011 ))) =解释为(负(反转位( 1000_0011 )))
  • =interpret-as(negative( 0111_1100 )) =解释为(否定( 0111_1100 ))
  • =interpret-as(negative(124)) =解释为(否定(124))
  • =interpret-as(-124) =解释为(-124)
  • =-124 Tada!!! =-124多田!!!

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. Java 中的字节是有符号的,因此它的范围是 -2^7 到 2^7-1 - 即 -128 到 127。由于 132 大于 127,所以最终会环绕到 132-256=-124。 That is, essentially 256 (2^8) is added or subtracted until it falls into range.也就是说,本质上增加或减少了 256 (2^8) 次,直到它落入范围内。

For more information, you may want to read up on two's complement .有关更多信息,您可能需要阅读二进制补码

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. 132 超出了 -128 到 127(Byte.MIN_VALUE 到 Byte.MAX_VALUE)的字节范围,而是将 8 位值的最高位视为有符号的,这表明在这种情况下它是负数。 So the number is 132 - 256 = -124.所以数字是 132 - 256 = -124。

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.只复制最右边的 8 位 (LSB) 并丢弃其余的。
  3. From the result of step#2, if the leftmost bit is 0, then use a calculator to convert the number to decimal.从步骤#2 的结果来看,如果最左边的位是 0,则使用计算器将数字转换为十进制。 This is your answer.这是你的答案。
  4. Else (if the leftmost bit is 1) your answer is negative.否则(如果最左边的位是 1)你的答案是否定的。 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.并将其余的颠倒过来,即用0代替1,用1代替0。 Then use a calculator to convert to decimal and append a negative sign to indicate the value is negative.然后使用计算器转换为十进制并附加一个负号表示该值为负数。

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 个步骤绝对不是模运算。

Two's complement Equation:补码方程:

在此处输入图片说明


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, a 7 is negative for byte but positive for int .从等式来看,a 7byte是负数,但对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

often in books you will find the explanation of casting from int to byte as being performed by modulus division.通常在书中,您会发现从 int 转换为 byte 的解释是由模数除法执行的。 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 数字的二进制值中的 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);

    }

}

}

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 daixtr answer.看看daixtr 的回答。 A implementation of exact algorithm discribed in his answer is the following:他的回答中描述的精确算法的实现如下:

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;
}

If you want to understand this mathematically, like how this works如果你想从数学上理解这一点,比如它是如何工作的

so basically numbers b/w -128 to 127 will be written same as their decimal value, above that its (your number - 256).所以基本上数字 b/w -128 到 127 将与其十进制值相同,高于其(您的数字 - 256)。

eg.例如。 132, the answer will be 132 - 256 = - 124 ie 132,答案是 132 - 256 = - 124 即

256 + your answer in the number 256 + (-124) is 132 256 + 你在数字 256 + (-124) 中的答案是 132

Another Example另一个例子

double a = 295.04;
int b = 300;
byte c = (byte) a;
byte d = (byte) b; System.out.println(c + " " + d);

the Output will be 39 44输出将是 39 44

(295 - 256) (300 - 256) (295 - 256) (300 - 256)

NOTE: it won't consider numbers after the decimal.注意:它不会考虑小数点后的数字。

Conceptually, repeated subtractions of 256 are made to your number, until it is in the range -128 to +127.从概念上讲,对您的数字进行 256 的重复减法,直到它在 -128 到 +127 的范围内。 So in your case, you start with 132, then end up with -124 in one step.因此,在您的情况下,您从 132 开始,然后一步以 -124 结束。

Computationally, this corresponds to extracting the 8 least significant bits from your original number.在计算上,这对应于从原始数字中提取 8 个最低有效位。 (And note that the most significant bit of these 8 becomes the sign bit.) (请注意,这 8 个中的最高有效位成为符号位。)

Note that in other languages this behaviour is not defined (eg C and C++).请注意,在其他语言中,此行为未定义(例如 C 和 C++)。

  1. In java int takes 4 bytes=4x8=32 bits在java中int需要4个字节=4x8=32位
  2. byte = 8 bits range=-128 to 127字节 = 8 位范围 =-128 到 127

converting 'int' into 'byte' is like fitting big object into small box将“int”转换为“byte”就像将大对象装入小盒子

if sign in -ve takes 2's complement如果登录 -ve 取 2 的补码

example 1: let number be 130示例 1:让数字为 130

step 1:130 interms of bits =1000 0010步骤 1: 130 位 = 1000 0010

step 2:condider 1st 7 bits and 8th bit is sign(1=-ve and =+ve)步骤 2:考虑第 1 个 7 位和第 8 位是符号(1=-ve 和 =+ve)

step 3:convert 1st 7 bits to 2's compliment第 3 步:将第 1 个 7 位转换为 2 的补码

            000 0010   
          -------------
            111 1101
       add         1
          -------------
            111 1110 =126

step 4:8th bit is "1" hence the sign is -ve第 4 步:第 8 位为“1”,因此符号为 -ve

step 5:byte of 130=-126步骤5:130的字节=-126

Example2: let number be 500示例 2:让数字为 500

step 1:500 interms of bits 0001 1111 0100步骤 1:500 位 0001 1111 0100

step 2:consider 1st 7 bits =111 0100第 2 步:考虑第 1 个 7 位 =111 0100

step 3: the remained bits are '11' gives -ve sign第 3 步:剩下的位是 '11' 给出 -ve 符号

step 4: take 2's compliment第 4 步:接受 2 的赞美

        111 0100
      -------------
        000 1011 
    add        1
      -------------
        000 1100 =12

step 5:byte of 500=-12第 5 步:500 的字节=-12

example 3: number=300示例 3:数字=300

 300=1 0010 1100

 1st 7 bits =010 1100

 remaining bit is '0' sign =+ve need not take 2's compliment for +ve sign

 hence 010 1100 =44

 byte(300) =44
 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           

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM