Android [转] Java 中 100 等于 100,200 不等于 200?

xinggang · 2016年12月14日 · 92 次阅读

最近玩出来了一个极其诡异的现象,如下图所示:第一行输出的结果是 true,而第二行输出的结果是 false。如此简单的几行代码,却产生如此奇怪的结果,难道 JDK 会有如此低级的 BUG?可能吗?当然不可能,本着打破砂锅问到底的精神,我们来一起一探究竟。
12d70007f4f194ab364c
我们知道 Java 里面==符号比较两个引用对象的话是比较的是否为同一个对象,而如果比较值是否相等应该用 equals。这里 100 的情况下结果是 true,而 200 的结果是 false,说明图中引用 a1 和 a2 指向的是同一个对象,而引用 b1 和 b2 指向的是不同的对象,只不过它们的值都是 200。那么是不是这样呢?首先使用 JDK 自带的 javap 命令查看一下生成的 class 文件
javap -verbose Main
得到如下图结果:
12d70007f4f6c99c5ab1
Integer a1 = 100 对应的指令为:

0: bipush 100
2: invokestatic #16 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;

Integer b1 = 200 对应的指令为:

12: sipush 200
15: invokestatic #16 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;

bipush 指令意思是将单字节的常量值 (-128~127) 推送到栈顶
sipush 指令意思是将短型的常量值 (-32768~32767) 推送到栈顶
invokestatic 指令意思是调用静态方法,这里调用的是常量池中 #2 指向的方法 java/lang/Integer.valueOf,于是查看 JDK 源码中的 Integer.valueOf 方法:
12db00001f5c2fe5087f
当输入的参数大于等于 IntegerCache 的 low,小于等于 IntegerCache 的 high 时,从 IntegerCache 中取对象,否则重新 new 出一个 Integer 对象。从 IntegerCache 的构造函数可以看出 IntegerCache.low=-128,不另外配置的默认情况下 high 值为 127,即,输入在 [-128,127] 之间时从缓存中取 Integer 对象,否则 new 出新对象。
原来如此,a1 和 a2 都是从 IntegerCache 中取出来的同一个对象,而 b1 和 b2 是 new 出来的不同对象,这也就解释了为什么第一行输出 true,而第二行输出 false。

暂无回复。
需要 登录 后方可回复, 如果你还没有账号请点击这里 注册