Java如何将int转换为字节?
int i =132; byte b =(byte)i; System.out.println(b);
输出是-124
这是为什么? 我知道这是一个非常基本的问题,但是我仍然无法对其进行映射,或者了解这是怎么回事?
在Java中, int
是32位。 一个byte
是8 bits
。
Java中的所有东西都是有符号的,而byte
s, int
s, long
s是用二进制补码编码的。
在这个数字表格中,最重要的位指定了数字的符号。 如果需要更多位,则最高有效位(“MSB”)将被复制到新的MSB。
所以如果你有字节255
: 11111111
并且你想把它表示为一个int
(32位),那么你只需要简单地将1复制到左边24次。
现在,读取负数的二进制数的一种方法是从最低有效位开始,向左移动,直到find第一个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读取为正值。
为了理解它是如何工作的,我们需要知道计算机的工作原理。
基数10 (十进制)中的132是基数2 (二进制)中的10000100
。 由于Java以32位存储int
,所以我们拥有的是
00000000_00000000_00000000_10000100
当一个int
被转换成一个byte
,Java会截断最左边的24位。 我们得到的是10000100
。
在二进制补码中 ,最左边的位用作符号。 如果最左边的位是0
,则不会做任何进一步的处理。
如果最左边的位是1
(就像我们这里所说的那样),这意味着这个数字是负数,需要做更多的工作。 为了得到这个幅度,我们减去一个然后应用补码 (应用补码意味着我们反转比特):
-
10000100
– 1 =10000011
-
反转
10000011
=01111100
当解释为十进制数时,是01111100
,是124。
所以我们有一个124的负数,给我们-124 。
Java中的字节是有符号的,所以它的范围是-2 ^ 7到2 ^ 7-1 – 也就是-128到127.因为132在127以上,所以最后到132-256 = -124。 也就是说,基本上256(2 ^ 8)被添加或减去,直到它落入范围。
欲了解更多信息,您可能需要阅读补充 。
132在-128到127(Byte.MIN_VALUE到Byte.MAX_VALUE)的字节的范围之外。相反,在这种情况下,8位值的最高位被视为负值。 所以这个数字是132 – 256 = -124。
通常在书中,你会发现从模拟到字节的解释是由模数分割执行的。 这不是严格正确的,如下所示实际发生的是,如果剩下的最左边的位被设置,那么来自整数的二进制值的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); } } }
这是一个非常机械的方法,没有分散注意力的理论:
- 将数字转换为二进制表示(使用计算器可以吗?)
- 只复制最右边的8位(LSB)并丢弃其余部分。
- 从步骤#2的结果来看,如果最左边的位是0,则使用计算器将该数字转换为十进制。 这是你的答案。
- 否则(如果最左边的位是1),你的答案是否定的。 保留所有的最右边的零和第一个非零位不变。 剩下的就是倒过来,就是用1代替1,用0代替1。 然后使用一个计算器转换为十进制,并附加一个负号表示该值为负值。
这个更实用的方法是根据上面的很多理论的答案。 所以,那些还在读这些Java模式的人说,这是绝对错误的,因为我上面提到的4个步骤绝对不是模操作。
二补数方程:
在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
模拟其工作方式的快速algorithm如下:
public int toByte(int number) { int tmp = number & 0xff return (tmp & 0x80) == 0 ? tmp : tmp - 256; }
这是如何工作的? 看看daixtr的答案。 在他的回答中描述的精确algorithm的实现如下:
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; }
从概念上说,重复减去256是你的号码,直到它在-128到+127的范围内。 所以在你的情况下,你从132开始,然后一步到达-124。
在计算上,这相当于从原始数字中提取8个最低有效位。 (并且注意这8个中最重要的一点是符号位。)
请注意,在其他语言中,这种行为没有定义(例如C和C ++)。
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