我们在进行Java编程的时候,使用最频繁的数据类型基本上就是int型了。平时在使用这种数据类型的过程中,我们似乎也并没有感觉到有什么太多需要注意的地方,其实int类型的变量在使用过程中也会有一些隐藏很深的坑,我们通过一篇短文来了解一下。
首先我们先来明确一下Java虚拟机在对int型数据进行处理时默认的两条规则
- 当程序出现“整型常量”的时候,默认都是以int型存储的
- 如果算术表达式中出现的所有的数字都是int型的,默认运算结果也是int类型
了解了这两条基本规则之后,我们接着往下看。在程序编译过程中,编译器只对“直接出现”的int常量进行数据超范围检查,而对“运算产生的int型值”并不进行超范围检查。这句话是什么意思呢?我们来看下面的代码
我们使用数字2200000000给long类型的变量x赋值,2200000000其实并没有超过long类型数据的范围,但是编译器却认为这条语句有语法错误,为什么呢?刚才我们强调过:当程序出现“整型常量”的时候,默认都是以int型存储的,这个2200000000就是一个“整型常量”,所以编译器会把它当作int型数据来看待,尽管它最终被赋值给了long类型的变量。刚才说过,编译器会对“直接出现”的int常量进行数据超范围检查,这个2200000000就是“直接出现”在程序中的,并且还被当作了int型,所以编译器要对其进行检查,经检查发现这个数字已经超过了int型的表示范围,所以会报错。
修改这个错误的办法也很简单,只要在2200000000后面加一个字母L就可以让它转换为long类型数据,这样语法错误自然消失。那么,既然编译器已经已经用如此明显的形式给我们报错,我们当然能排除掉错误,但是对于编译器不报错的情况,我们很有可能就会“掉坑”,来看下面的代码:
我们希望计算一天有多少微秒(1秒=1百万微秒),于是我们给出了上面的计算公式,并且考虑到计算结果会超过int类型的表示范围,我们很小心的把计算结果保存到了一个long类型的变量当中。首先明确,这个计算结果是86400000000,它并没有超过long类型数据的表示范围,但是,运行结果如下图,是一个完全错误的数值
这是为什么呢?刚才已经强调过:算术表达式当中,如果全部是int类型的数据进行运算,那么运行结果也是int类型的。现在程序中的算术表达式就是典型的这种情况:全部由int类型的数据参与运算,所以运算结果也是int类型的。虽然明白了这个道理,但是还是没说清楚计算结果为什么如此“不靠谱”。解释这个现象,就必须用到我们刚才所说的一条规则:编译器对“运算产生的int型值”并不进行超范围检查。在运算过程中,因为全部数据都是int型,所以每一步运算结果都会被保存到一个int型的临时变量当中。但是因为每一步的运算结果都不是“直接出现的数字”,所以编译器对每一步运算结果都不做超范围检查,那么,算着算着,相乘的结果不知不觉就已经超过了int类型的表示范围,虽然超过了范围,但编译器坐视不理,仍然进行赋值。把一个超范围的数据赋值给int型的临时变量会导致“溢出”现象,也就是说,运算结果超范围的高位部分被丢弃了,只保留了低位数据,从而导致产生了一个错误结果。所以,我们不能简单认为理论上的计算结果86400000000没有超过long类型数据的表示范围,就可以直接把这些int型数据直接进行相乘并赋值。消除这个程序错误的方法也很简单,就是把乘法表达式当中任意一个乘数因子的后面加上字母L,使其变成一个long类型的数据就可以了。一旦编译器发现有long类型的数据参与了运算,就不会把运算结果看作是int型,而是自动提升为long类型。这样就不会出错了。
关于int型数据,还有一个隐藏很深的大坑,大家来看代码
这个循环看似只能执行101次,其实它是一个无限循环(死循环)!原因就是2147483647是int类型数据所能表示的最大值,而循环变量i在到达最大值以后,再进行加1操作,得到却是-2147483648!这导致i永远都会满足循环条件,从而使看起来有限次数的循环变成了无限。至于为什么在int型最大值的基础上再加1会变成-2147483648,大家可以看《Java千问06:Java语言中最大的整数再加1等于多少?看完秒懂!》,这里就不详细解释了。
看完这篇文章之后,是不是有一种被惊出一身冷汗的感觉呢?所以千万不要小看一个简单的int类型哟!