我们都知道计算机存储的是二进制,长度是8个比特。
byte b = 10;
int i = -10;
long l = 10L;
那么以上几个变量如何用二进制表示呢?
很多人第一印象肯定是 b变量占用一个字节,也就是8位,所以 b用二进制表示就是 1010,高位补零,所以是 00001010。那么i是int,占用4个字节,也就是32位,但因为是负数,所以最高位是100000000 00000000 00000000 00001010。同理 l变量则是 00000000 00000000 00000000 00000000 000000000 00000000 00000000 00001010。
上面的推理过程中存在一处错误,就是在java中存储的是补码,而不是原码。正数的原码,反码和补码相同。负数则不是一样。以上面 int i = -10 作为例子。
变量 i
原码 1000 1010
# 反码是符号位不变,其他位取反
反码 1111 0101
#补码则是在反码的基础上加1
补码 1111 0110
所以-10 在计算机中正确的表示应该是 1111 0110。
上面我们已经学习原码,反码和补码相关的概念,至于为什么要用补码,感兴趣的可以自己去查。
我们也知道在网络传输中,存储的就是二进制相关的byte数组。那么现在我们需要往消息中写入int或者long相关的信息,如何转换为byte数组中的相关项?第一个想到的办法就是强制转换。
int x = 135;
System.out.println((byte)x); /** 输出-121 **/
x = -135;
System.out.println((byte)x); /** 输出-121 **/
可见输出的答案并不如你所愿。想知道为什么这样吗?感兴趣的可以自己去推导。
额,还是帮你们推导一遍吧。我们以 -135为例。
首先我们知道 int 占用4个字节,而byte占用1个字节,同时你也看到 -135已经超出了一个字节所能表示的范围[-128, 127]。如果强制转换后还能显示出正确结果,那才恐怖啊。
-135
原码 10000000 00000000 00000000 10000111
反码 11111111 11111111 11111111 01111000
补码 11111111 11111111 11111111 01111001
我们知道java中存储的是补码,可是因为byte只占一个字节,所以转换的时候只取到最低位那个字节也就是 01111001作为转换后补码存在。因为正数的原码和补码相同,也即是这个字节的原码是01111001,原值是 121。
刚才我们讨论的是int强制转换成byte类型可能存在的问题。那么如果我需要把byte类型的强制转换成int类型的会出现什么样的问题。
byte num = 120;
System.out.println((int)num);
num = -120;
System.out.println((int)num);
大家看到这两行示例代码时。尽量自己尝试推导出结果来,不要看我下面的推导过程。
我们以-120作为例子,尝试推导下(看到没有,我喜欢负数)。
-120
原码 11111000
反码 10000111
补码 10001000
##此刻开始转换为int类型,占4个字节,符号位1,用1填充高位三个字节。如果符号位是0,高位会用0填充。
补码 11111111 11111111 11111111 10001000 /** 存储在内存中的int整形补码 **/
反码 11111111 11111111 11111111 10000111
原码 10000000 00000000 00000000 01111000
原值 -120
所以 当 byte num = -120 时, (int)num = -120
我相信很多人都没有自己推导,直接看我的推导的。那么再给你个机会,尝试推导下当byte num = 120的时候推导过程。
通过byte强制转换成int 好像一切都很顺利,也没有int强制转换成byte相关的问题。
当真的是那样吗?下一篇我们继续探讨这个话题。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。