int i =132;
byte b =(byte)i; System.out.println(b);
令人费解。为什么输出是-124
?
int i =132;
byte b =(byte)i; System.out.println(b);
令人费解。为什么输出是-124
?
int
是32位。一个byte
是8个bits
。byte
、short
、int
和long
使用二进制补码表示。( char
类型是无符号的,而boolean
没有概念)。byte
为255
:11111111
,并且你想将它表示为一个int
(32位),你只需将1向左复制24次。11111111
变为00000001
=-1
。这是Java将显示的值。byte signedByte = -1;
int unsignedByte = signedByte & (0xff);
System.out.println("Signed: " + signedByte + " Unsigned: " + unsignedByte);
将会打印出:"Signed: -1 Unsigned: 255"
这里到底发生了什么?
我们使用按位与运算来屏蔽所有多余的符号位(也就是最不重要的八个二进制位左边的那些1)。当一个int类型转换成byte类型时,Java会截取掉最左边的24个位。
1111111111111111111111111010101
&
0000000000000000000000001111111
=
0000000000000000000000001010101
由于现在的第32位是符号位而不是第8位(并且我们将符号位设为了0表示正数),Java会将字节中原来的8位作为一个正值读取。
132
在十进制(10进制)中,对应的二进制(2进制)表达式为1000_0100
,而Java将int
存储在32位中:
0000_0000_0000_0000_0000_0000_1000_0100
int
转换为byte
的算法是左截断;在System.out.println
中使用的算法是二进制补码(如果最高位是1
,则解释为负数:取反码(翻转比特)减去一。)因此System.out.println(int-to-byte(
))
为:
1
)[负数(取反码(减一(左截断(0000_0000_0000_0000_0000_0000_1000_0100
)))))1
)[负数(取反码(减一(1000_0100
))))]1000_0011
))))0111_1100
)))int
到byte
的转换是有损转换(即信息丢失)。因此,无法将其转换回原始的int
值。 - daparic在Java中,byte是有符号的,它的范围是从-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。
这里提供一种非常机械的方法,没有那些令人分心的理论:
这种更实用的方法符合上面许多理论性答案的要求。所以,那些仍在读那些声称使用模数的Java书籍的人,这明显是错误的,因为我概述的4个步骤绝对不是模操作。
http://iiti.ac.in/people/~tanimad/JavaTheCompleteReference.pdf
第59页。 - daparic在Java中,byte
(N=8)和int
(N=32)均采用了上述二进制补码表示。
由于上述公式,对于byte
而言,a7是负数,但对于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
public int toByte(int number) {
int tmp = number & 0xff
return (tmp & 0x80) == 0 ? tmp : tmp - 256;
}
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;
}
在很多书籍中,你会看到将整型转换为字节的解释被视为模除操作。然而,这并不严格正确,如下所示: 实际发生的是将整数值的二进制形式中最高的24位被丢弃,导致剩余的最左边的一位可能被设置为1,表示该数字为负数,从而造成混淆。
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);
}
}
}
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)
注意:它不会考虑小数点后面的数字。
signedByte & (0xff)
,其中0xff
是一个整数字面量,因此在执行位运算之前,signedByte 会被提升为整数。 - Kevin Wheeler