理解Java虚拟机整数表示的前置内容
在Java的虚拟机中,整数有byte、short、int、long四种,分别表示8位、16位、32位、64位有符号整数。整数在计算机中用补码表示,在Java虚拟机中也不例外。在学习补码之前,必须先理解原码和反码。
原码
所谓原码,就是符号位加上数字的二进制表示。以int为例,第1位表示符号位(正数或者负数),其余31位表示该数字的二进制值。
10的原码为: 00000000000000000000000000001010
-10的原码为:10000000000000000000000000001010
对于原码来说,绝对值相同的正数和负数只有符号位不同。
反码
反码就是在原码的基础上,符号位不变,对其余位取反,以-10为例,其反码为:
11111111111111111111111111110101
补码
负数的补码就是反码加1,整数的补码就是原码本身。
因此,10的补码为:
00000000000000000000000000001010
而-10的补码为
11111111111111111111111111110110
在Java中,可以使用位运算查看整数中每一位的实际值,方法如下:
1 public static void printBinary(int number) {
2 for (int i = 0; i < 32; i++) {
3 int t = (number & 0x80000000 >>> i) >>> (31 - i);
4 System.out.print(t);
5 }
6 }
以上代码将打印 -10 在虚拟机内的实际表示,程序的执行结果如下:
11111111111111111111111111110110
可以看到这个结果和之前的补码计算是完全匹配的。
这段程序的基本思想是:进行32次循环(因为int有32位),每次循环取出int值中的第一位,第三行的 0x80000000 是一个 首位为1、其余位为0的整数,通过右移i位,定位到要获取的第i位,并将除该位的其他位统一设置为0,而该位不变,最后将该位移至最后,并运行输出。
相对于原码,使用补码作为计算机内的实际存储方式至少有以下两个好处:
(1)可以统一数字0的表示。由于0既非正数,又非负数,使用原码表示时符号位难以确定,把0归入整数或者负数得到的原码结果是不同的。但是使用补码表示时,无论把0归入正数还是负数都会得到相同的结果。计算过程如下:
如果0为正数,则补码为原码本身:00000000000000000000000000000000
如果0为负数,则补码为反码加1,负数的0的原码为:10000000000000000000000000000000
反码为:11111111111111111111111111111111
补码在反码的基础上加1,结果为:00000000000000000000000000000000
可以看到,使用补码作为整数编码,可以解决数字0的存储问题。
(2)使用补码可以简化整数的加减法计算,将减法计算视为加法计算,实现减法和加法的完全统一,实现正数和负数加法的统一。先使用8位(byte)整数说明这个问题。
计算-6+5的过程如下:
-6的补码:11111010
5的补码:00000101
直接相加得:11111111
通过计算可知,11111111表示-1
计算4+6的过程如下:
4的补码:00000100
6的补码:00000110
直接相加得:00001010
通过计算可知,000001010表示10(十进制)。
可以看到,使用补码表示时,只需要将补码简单地相加,即可得到算术加法的正确结果,而无须区别正数或者负数。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。