bug?
前几天有位朋友找我,说:“老哥,老哥,我好像发现了Integer一个bug,你帮我看看什么情况?”,说完给了我两个很简单的demo,上代码。
100 == 100
1000 == 1000
通过代码,我们可以看到,这是很简单的“100100”、“10001000”,但是为什么一个是“true”,一个是“false”,难道真的是bug?
使用Integer的场景
我们平时用Integer,都是用来操作整型数值相关操作,比如Model里面的自增主键id,类型标识type等等。
比如我们有个类型,性别,1 男 2 女;那么我们展示到页面的代码一般会这么写:
public static final Integer MAN = 1;
public static final Integer WOMAN = 1;
... ...
if(MAN == user.getSex()) {
return "男";
} else if(WOMAN == user.getSex()) {
return "女";
}
很常见,基本也没遇到过问题,因为我们也很少类型超过几百上千的,只有特殊场景的设计才有。
Integer是什么,怎么正确比较
我们先看看Integer的定义,打开Integer的源代码文件:
class Ineger
通过截图中的代码,我们可以看到,Integer是class,所以Integer是对象。
我们都知道对象的“==”比较,是比较的两引用对象的指针(内存地址)是否相等,也就是是否指向同一对象。既然是对象,那么Integer的正确比较姿势,肯定是“equals”了,即“a.equals(b)”。
我们再回头看前面的例子,“a”和“b”并不是同一个对象。那为什么“100”可以,“1000”就不可以?
自动装箱拆箱
装箱,是自动将基本数据类型转换为包装器类型;
拆箱,是自动将包装器类型转换为基本数据类型;
在这里我们不对“装箱拆箱”做太多的解释,后续我们再开专题讨论。
回到Integer,简单了解下其装箱拆箱分别做了什么操作。
Integer类型的赋值给int类型,调用intValue()方法进行拆箱赋值;
int类型赋值给Integer,会调用valueOf()方法对int进行装箱赋值。
看下相应的源码:
intValue()
valueOf()
我们可以看到,除了“return new Integer(i)”,还有一段if判断,大致意思我们可以看出来,当在“IntegerCache.low”与“IntegerCache.high”区间的时候,会返回“IntegerCache.cache[]”的一个值。
好了,到此,我们可以看到,当装箱 Integer 的值在一定区间的时候,并不是“new”出来的,而是从 IntegerCache.cache[] 中取出来的。所以我们再看看 IntegerCache 是如何定义的。
Integer 缓冲池 IntegerCache
话不多说,先上源码:
IntegerCache
由于时间有限,我们就看看重点,
for(int k = 0; k < cache.length; k++)
cache[k] = new Integer(j++);
这两行代码,就是初始化了cache[]数组的值,每个值都是对应的数值的Integer对象。
1000 不等于 1000 还是bug吗?
到此,我们已经得知,几个重点:
- Integer 是对象
- Integer 值比较应该使用 equals()
- Integer 有个缓存池 IntegerCache,预初始化 -127 至 127 的 Integer 对象\
再看看demo,使用的是“==”并不是“equals()”,所以这并不是bug,而是比较的方式不对,正确的比较姿势是“equals()”,我们来实践一下看看。
举一反三
同样是装箱拆箱,Long是否也有缓存池呢?Double呢?