- 你来猜?
Integer i = 127;
Integer j = 127;
i == j 答案是true还是false呢?如果是128呢?
昨晚在书上看到这么一个问题,感觉很有意思,呵呵。书上没有答案,我默算肯定两者都是true,后来跑了一下代码,奇迹出现了,还果然出了我的料。前者竟然是true,而后者是false。心理不踏实,便探个究竟。直接javap –verbose TestEqual这个类,发现对应的jvm指令基本上一致。没发现啥特殊之处,我想两者区别不应该体现在指令层面。虽然如此,但我发现有这个一个地方:
即,127被赋值给变量i或者j的时候,装箱成为了Integer,从上图中很容易看出调用Integer.valueOf(int)这个方法,返回值为Integer。所以我从这里展开追踪,哈哈。有了:
其中:IntegerCache.low = -128;
- 注意到这里有个范围的控制,似乎是在这个范围中的数字,直接从缓存(Integer.cache)中取,而在范围之外的采用new的方式。关于new的方式我们都知道,会有一个新地址的出现。
- 从上面断言assert IntegerCache.high >= 127;强制要求high的下界为127,同时这个数值也是缓存的上界。
现在继续,来看这个缓存的设置:
在缓存初次被使用的时候,就会被初始化了,如果没有通过设置属性来控制最大数值默认最大的数值为127。所以jvm为了性能的目的,将-128到127 Integer数值缓存起来了。i == j,只要是属于这个区间的肯定返回true,因为虽然==比较的是地址( ),但他们确实是同一个地址。呵呵。所以我们最初问题的答案到这里便揭晓了,呵呵。
- 不妨多想一下,看看Byte、Short、Long、Float、Double有没有同样的缓存机制呢?
看了一下jdk源码,发现Byte、Short和Long采用同样的机制,唯一不同的地方就是上界128是写死的。而Float和Double没有采用该机制。
- 既然说可以通过配置来扩大Integer的缓存上界,那就体验一把吧。
通过这个选项皆可以扩容了,呵呵。-XX:AutoBoxCacheMax=500,于是乎我在eclipse中配置了vm参数:
结果出现:
俺不懂了,于是乎上网查了一下,原来这个参数适应于server模式,不适合client模式,哈哈。好吧,改为:
-server -XX:AutoBoxCacheMax=500
哈哈,大功告成了:
Integer i = 128 和 Integer j = 128, 相等了。