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

时间:2009-05-09 06:33:59

标签: java

int i =132;

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

Mindboggling。为什么输出-124

12 个答案:

答案 0 :(得分:165)

在Java中,int是32位。 byte为8 bits

Java中的大多数原始类型都是签名的,byteshortintlong以二进制补码编码。 (char类型是无符号的,符号的概念不适用于boolean。)

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

所以如果你有字节25511111111 并且您希望将其表示为int(32位),只需将1复制到左侧24次。

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

例如:11111111转到00000001 = -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读取为正值。

答案 1 :(得分:87)

数字(base 10)中的

1321000_0100位(base 2),Java存储int为32位:

0000_0000_0000_0000_0000_0000_1000_0100

int-to-byte的算法是left-truncate; System.out.println的算法是two's-complement(如果最左边的位是1则是二进制补码,解释为负one's-complement(反转位)减-1。);因此System.out.println(int-to-byte( ))是:

  • interpre-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 [)))))
  • =解释-AS(负(反转位(减一(1000_0100))))
  • =解释-AS(负(反转位(1000_0011)))
  • =解释-AS(阴性(0111_1100))
  • =解释-AS(负(124))
  • =解释-AS(-124)
  • = - 124 Tada !!!

答案 2 :(得分:23)

Java中的

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

有关详细信息,您可能需要阅读two's complement

答案 3 :(得分:16)

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

答案 4 :(得分:3)

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

  1. 将数字转换为二进制表示(使用计算器确定?)
  2. 仅复制最右边的8位(LSB)并丢弃其余部分。
  3. 从步骤#2的结果开始,如果最左边的位为0,则使用计算器将数字转换为十进制。这是你的答案。
  4. 否则(如果最左边的位为1),您的答案是否定的。保留最右边的零和第一个非零位不变。并颠倒了其余部分,即用0和0代替1和0。然后使用计算器转换为十进制并附加一个负号以表示该值为负。
  5. 这种更实用的方法符合上面的理论答案。所以,那些仍在阅读那些使用modulo的Java书籍的人,这绝对是错误的,因为我上面概述的4个步骤绝对不是模运算。

答案 5 :(得分:3)

Two's complement Equation:

enter image description here

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

从等式中, 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

答案 6 :(得分:2)

通常在书中你会发现从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);

    }

}

}

答案 7 :(得分:2)

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

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

这怎么工作?期待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;
}

答案 8 :(得分:0)

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

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

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

答案 9 :(得分:0)

如果您想从数学上理解它,例如它是如何工作的

因此基本上b / w -128到127的数字将与它们的十进制值相同,高于其十进制值(您的数字-256)。

例如132,答案将是 132-256 =-124 即

256 +您的电话号码答案 256 +(-124)是132

另一个例子

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

输出将为39 44

(295-256)(300-256)

注意:它将不考虑小数点后的数字。

答案 10 :(得分:0)

  1. 在java中int需要4个字节=4x8=32位
  2. 字节 = 8 位范围 =-128 到 127

把'int'转换成'byte'就像把大对象装进小盒子

如果登录 -ve 取 2 的补码

示例 1:让数字为 130

第 1 步:130 位 =1000 0010

第 2 步:判断第 1 个 7 位和第 8 位是符号(1=-ve 和 =+ve)

第 3 步:将第 1 个 7 位转换为 2 的补码

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

第 4 步:第 8 位为“1”,因此符号为 -ve

第 5 步:130 的字节=-126

示例 2:让数字为 500

步骤 1:500 位 0001 1111 0100

第 2 步:考虑第 1 个 7 位 =111 0100

第 3 步:剩下的位是 '11' 给出 -ve 符号

第 4 步:接受 2 的赞美

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

第 5 步:500 的字节=-12

示例 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

答案 11 :(得分:-1)

 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