您的位置:首页 > 编程语言 > Java开发

由一个死循环引出的一系列问题及思考

2018-02-05 16:45 351 查看
一次粗心引起的死循环

场景

一次系统升级中,需要修改一个需求,而这个需求需要修改一个for循环的次数,原循环如下:

for(byte i = 0 ; i < 30 ; i++){
//do something
}


而修改后如下:

for(byte i = 0 ; i < 300 ; i++){
//do something
}


老司机很轻易的就能知道哪儿有问题,但是因为我的粗心,导致当时没有发现这个问题,造成了死循环,不过还好改的地方不多,几分钟就找到了这个地方。

问题原因

第二个为什么是死循环呢?这与java中数据类型的存储有关,byte类型的数值最多8位(二进制位),也就是byte的最大值也就是2^8 = 256了,有的同学可能会说,不对啊,java中byte不是-128~127吗,是的因为java中的number类型都是有符号的,所以符号位要占一位,也就是说java中的byte除去符号位其实也就7位,所以byte值也就是-128~127了,所以这个循环是永远不可能满足退出条件i
< 300的,因此造成了死循环。

再来说开篇的问题,第一个for循环退出条件是i < 30,这个是没问题的,但是修改的时候没有看i的类型,直接将for循环的退出条件修改为了i < 300,i的最大值也就127了自然是不会大于300了,所以修改后这个for循环就成为了一个死循环。

扩展

可能有的同学会问,既然byte类型的最大值是127,那么byte类型的127加1后是多少?这个其实可以自己把二进制写出来然后加一下答案就有了
127的二进制表示:

0111 1111

加1后的二进制表示:

1000 0000

因为最高位是符号位,所以可以知道该数值是一个负数,而对于一些同学可能知道以下概念:


原码

原码表示法在数值前面增加了一位符号位(即最高位为符号位):正数该位为0,负数该位为1(0有两种表示:+0和-0),其余位表示数值的大小。例如:八位的情况下

    +1表示为:

        0000 0001

    -1表示为:

        1000 0001

看到这里,可能这部分同学想说,那上边的结果不就是-0了吗?但实际上并不是的,因为在计算机中实际对于负数并不是用的原码表示法,而是用的二补数(补码)。

首先我们需要了解以下概念:



补码

正整数的补码是其二进制表示,与原码相同,求负整数的补码,将其对应正数二进制表示所有位取反(包括符号位,0变1,1变0)后加1

有了以上概念就好算了,首先1000 0000最高位符号位是1,说明该值是一个负数,根据负数表示法逆推,想要得到正数需要先将该值减1,也就是:

1000 0000 - 1 = 0111 1111

然后将该值取反得到1000 0000

看到这里有的同学会问了,这不是跟没算一样吗?是的对于八位数来说1000 0000是个比较特殊的数字,他的补码还是他自己,但是你要仔细看概念,这样求得的数字是一个正数(求负数补码是在正数基础上求得的),也就是此时最高位的1就不用当符号位看了,所以对应的正数是128,加上原符号位也就是-128了。

同时也能发现,对于二补数来说是不存在-0的,因为任何一个非0二进制取反加1都不可能等于0(有兴趣的可以想一下为什么,很简单)。

至于为什么计算机采用二补数而不是原码表示法,可以自己思考一下,或者查询资料,或者加我的QQ群339634085我们一起讨论~~

附加


       
长按二维码关注我吧(微信公众号)
不要错过
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  J2EE J2SE java 算法