最近在项目中遇到了不太理解的地方,这里总结一下
问题
- 为什么int转byte可能是个负数
- &0xff的作用
- byte和int是怎么相互转化的
基础
在解释问题之前,了解一些计算机基础是很重要的
原码,反码,补码
数 | 原码 | 反码 | 补码 |
---|---|---|---|
+1 | 0000 0001 | 0000 0001 | 0000 0001 |
-1 | 1000 0001 | 1111 1110 | 1111 1111 |
- 正数反码补码原码相同
- 负数的反码是在其原码的基础上, 符号位不变,其余各个位取反.
- 负数的补码是在其原码的基础上, 符号位不变, 其余各位取反, 最后+1.
字节序(了解)
计算机硬件有两种储存数据的方式:大端字节序(big endian)和小端字节序(little endian)。
举例来说,数值0x2211使用两个字节储存:高位字节是0x22,低位字节是0x11。
两个知识点(重要)
- 计算机数的计算和存储是补码形式
- java只有有符号数
实例
有了上述概念,就可以举例说明了
int转byte可能是个负数
int a=233;
byte b=(byte)a;
System.out.println(b);//结果为-23
解析:
1.int是32位,233二进制补码形式(正数原码补码相同)
00000000 00000000 00000000 11101001[补码]
2.int转byte,byte是8位
(00000000 00000000 00000000) 11101001[补码]
3.去掉多余位数后剩下11101001[补码],求原码
11101001[补码]-> 10010111[原码] -> -23
&0xff的作用
- 只是为了取得低八位
- 保持补码一致性
byte和int是怎么相互转化的
int转byte
- 1246[补码] -> 00000000 00000000 00000100 11011110
- int是32位,byte是8位,所以将int转为byte需要4个字节
角标 | [0] | [1] | [2] | [3] |
---|---|---|---|---|
补码 | 00000000 | 00000000 | 00000100 | 11011110 |
真值 | 0 | 0 | 4 | -34 |
代码解析
int a =1246
byte[] b = new byte[4]
由于byte只有8位,int有32位,所以需要通过右移运算,把每8位一组的值,移动到最后8位来计算,其他位忽略
第一步,求b[0]的值:
补码 | 00000000 | 00000000 | 00000100 | 11011110 |
---|---|---|---|---|
右移24位 | 00000000 | 00000000 | 00000000 | 00000000 |
& 0xff | 00000000 | 00000000 | 00000000 | 00000000 |
代码
b[0] = (byte) (a >> 24 & 0xff ) //值为 0;
第二步,求b[1]的值:
补码 | 00000000 | 00000000 | 00000100 | 11011110 |
---|---|---|---|---|
右移16位 | 00000000 | 00000000 | 00000000 | 00000000 |
& 0xff | 00000000 | 00000000 | 00000000 | 00000000 |
代码
b[1] = (byte) (a >> 16 & 0xff ) //值为 0;
第三步,求b[2]的值:
补码 | 00000000 | 00000000 | 00000100 | 11011110 |
---|---|---|---|---|
右移8位 | 00000000 | 00000000 | 00000000 | 00000100 |
& 0xff | 00000000 | 00000000 | 00000000 | 00000100 |
代码
b[2] = (byte) (a >> 8 & 0xff ) //值为 4;
第四步,求b[3]的值:
补码 | 00000000 | 00000000 | 00000100 | 11011110 |
---|---|---|---|---|
右移0位 | 00000000 | 00000000 | 00000100 | 11011110 |
& 0xff | 00000000 | 00000000 | 00000000 | 11011110 |
由于是int转byte,去除多余24位后11011110[补码]求真值为-34
代码
b[3] = (byte) (a & 0xff ) //值为 -34;
完整代码
public static intToByteArr(int a){
byte[] b = new byte[4]
b[0] = (byte) (a >> 24 & 0xff )
b[1] = (byte) (a >> 16 & 0xff )
b[2] = (byte) (a >> 8 & 0xff )
b[3] = (byte) (a & 0xff )
return b;
}
byte[]转int
知道byte[] b = {0,0,4,-34}, 求int?只需把byte[]对应数的补码左移至原数对应的位置即可
第一步,b[0]对应的补码
补码 | 00000000 | 00000000 | 00000000 | 00000000 |
---|---|---|---|---|
& 0xff | 00000000 | 00000000 | 00000000 | 00000000 |
左移24位 | 00000000 | 00000000 | 00000000 | 00000000 |
代码
int a1 = (b[0] & 0xff )<<24 //值为 0;
第二步,b[1]对应的补码
补码 | 00000000 | 00000000 | 00000000 | 00000000 |
---|---|---|---|---|
& 0xff | 00000000 | 00000000 | 00000000 | 00000000 |
左移16位 | 00000000 | 00000000 | 00000000 | 00000000 |
代码
int a2 = (b[1] & 0xff )<<16 //值为 0;
第三步,b[2]对应的补码
补码 | 00000000 | 00000000 | 00000000 | 00000100 |
---|---|---|---|---|
& 0xff | 00000000 | 00000000 | 00000000 | 00000100 |
左移8位 | 00000000 | 00000000 | 00000100 | 00000000 |
代码
int a2 = (b[2] & 0xff )<<8 //值为 1024;
第四步,b[3]对应的补码
补码 | 11111111 | 11111111 | 11111111 | 11011110 |
---|---|---|---|---|
& 0xff | 00000000 | 00000000 | 00000000 | 11011110 |
代码
int a4 = (b[3] & 0xff ) //值为 222;
四个数相加起来结果1246
也可以这样理解
b[0]补码 | 00000000 | 00000000 | 00000000 | 00000000 |
---|---|---|---|---|
b[1]补码 | 00000000 | 00000000 | 00000000 | 00000000 |
b[2]补码 | 00000000 | 00000000 | 00000100 | 00000000 |
b[3]补码 | 00000000 | 00000000 | 00000000 | 11011110 |
逐个或运算 | 00000000 | 00000000 | 00000100 | 11011110 |
补码对应的真值也为1246
完整代码
public static byteArrToInt(int a){
int a1 = (a[0] & 0xff )<<24
int a2 = (a[1] & 0xff )<<16
int a2 = (a[2] & 0xff )<<8
int a3 = (a[3] & 0xff )
return a1|a2|a3|a4;
}