已知Java语言中int类型所能表示的大整数为2147483647,请问以下代码执行结果是什么?
一部分人都会认为这段程序压根就无法通过编译,也有人认为,这段程序能够通过编译,但在运行时会抛出异常,但更多的人面对这道题目根本就无从下手。那么正确答案是什么呢?首先告诉大家,这段程序能够顺利通过编译,并且在运行时也不会出现异常,运行的结果是在控制台上输出了数字-2147483648!而-2147483648正好是Java语言中int类型所能表示的最小整数。
这个运行结果可能会让很多人感到大跌眼镜,运行结果为什么会是这样的呢?想弄明白其中的原理,就必须先弄清楚Java语言中数字的表示和存储方式。
大家都知道:任何一个数字,存储到计算机当中,都是以二进制的形式进行存储的。在Java语言中,使用补码的形式来表示数字。那么补码是个什么东西呢?补码就是计算机用二进制的形式表示数字的一种规则。它的算法很简单:用最左边的一个二进制位表示数字的正负,0表示正数,1表示负数,我们把表示符号的这个二进制位叫做“符号位”,而剩余的二进制位表示数字本身。至于怎样用其余的二进制位表示数字,正数和负数略有区别。我们首先来说正数的情况。对于正数而言,直接用剩余二进制位表示这个数字就可以了。而对于负数而言,算法稍微复杂一点,分为两步:
一、用补码表示出这个数的绝对值,之后把每个位上的数字(连同符号位上的数字在内)按位取反,所谓按位取反就是如果这个位上原来是0,那么就变成1,如果原来这个位上原来是1,那么就变成0。
二、就是把这个取反以后的数字加上1,就得到了负数的补码表示结果。
没看懂?没关系!咱们用例子说事。首先必须知道,Java语言中int类型的数据占4个字节,那么4个字节所能表示的大整数是多少呢?按照补码的表示规则,这个大的整数存储到计算机当中应该是“1个0跟31个1”:
如果我们强行给这个数再加1,按照二进制的进位规则,它会变成下面的样子:
这个数是多少?会是0吗?我们来分析一下:首先最左边的符号位从0变成了1,所以可以肯定,这个数是个负数。那么一个正数做了加1的操作,它应该变成一个更大的正数,现在怎么变成负数了呢?我们必须清楚,原来这个数的符号位是0,是因为加法运算产生了“进位”,才使得符号位变成了1,但是,计算机不管那么多,它只要看到最左边的符号位是1,就认定这是一个负数。那么,这个负数的值是多少?我们可以按照补码表示负数的规则,以逆运算的方式求出它的绝对值,就知道这个负数的值了。
前面讲过:用补码表示负数的算法分两步进行,其中第二步,是在二进制数字上加1。那么反过来,这个过程的逆运算也要分两步进行。其中第一步就应该是在原负数补码的数字上减1,减1之后,刚才的数字就会变成下面的样子
补码求负数的第一步是对二进制数字按位取反,所以逆运算的第二步也是对各个位上的数字(连同符号位上的数字在内)按位取反,使得各个位数字恢复到原来的值。经过按位取反之后,刚才那个二进制数字又会变成下面的样子
细心的读者可能已经发现,折腾了半天,又回到了逆运算之前的样子!大家注意:表面上,这个二进制数跟逆运算之前是一个样,但是它的意义已经完全不同了。在进行逆运算之前,这个二进制数是一个补码形式表示的负数,而经过逆运算之后,这个二进制数变成了一个绝对值,既然是绝对值,它肯定不会是负数。因此,这个二进制数最前面的1并不表示负数,而是数字的一部分。那么这个绝对值是多少呢?转换成十进制就是2147483648。所以,我们图3中看到的那个“1开头后面跟着31个0”所表示的负数,就是-2147483648!
到此为止,我想大家已经明白为什么程序的运行结果是-2147483648了吧?可能有一部分读者会问:补码当中,“1开头后面跟着31个0”这个数字为什么不能解释为:符号位上的1表示负数,后面的31位数字表示0,这样形成的数字是-0,也就是0呢?其实,补码的运算规则中特意强调了这一点。规则强调:补码当中,对于0只有唯一一种表示形式,那就是32个0,其中最前面的0表示符号,后面的0表示数字。一旦遇到符号位是1,后面全是0的情况,必须按负数对待!既然要求我们按负数对待,那就必须通过逆运算来计算这个负数的绝对值。而我们计算得到的这个负数的绝对值就是2147483648。-2147483648是int类型的所能表示的最小值。因此,int类型数据的大值再加1,一下子就变成了int类型的最小值,我们可以戏称为“物极必反现象”。
那么,Java语言当中,其他三种类型的整数是否也有“物极必反现象”呢?对于long类型的变量来讲,也存在这种现象,而对于byte和short类型,我们使用其大值和1进行加法运算,无法再赋值给byte和short型的变量,因为这种操作在编译时就会报错。关于byte和short变量无法完成这种赋值操作的原因,大家可以看《Java千问:Java语言中为byte和short类型变量赋值为啥会报错?》进行详细了解。
另外,通过这个例子,大家也应该明白为什么Java语言中,整数类型的表示范围是不对称的。比如, byte类型的数据大值是是127,而最小并不是-127,而是-128。其原因就是补码规则中,把0当作了正数看待,这样的话正数这边有个0,而负数那边没有,从而表示范围不对称。
如果想系统学习Java编程,可以点击这里观看我的视频课程。有问题也可以加入我的QQ群291839907一起讨论。
创新互联www.cdcxhl.cn,专业提供香港、美国云服务器,动态BGP最优骨干路由自动选择,持续稳定高效的网络助力业务部署。公司持有工信部办法的idc、isp许可证, 机房独有T级流量清洗系统配攻击溯源,准确进行流量调度,确保服务器高可用性。佳节活动现已开启,新人活动云服务器买多久送多久。