Java中的整数缓存

63

可能是重复问题:
奇怪的Java装箱

最近我看到了一个Java代码示例,如下:

Integer a = 1000, b = 1000;  
System.out.println(a == b); // false  
Integer c = 100, d = 100;  
System.out.println(c == d); // true

我有点困惑。我理解第一个案例为什么结果是 "false" - 这是因为 Integer 是引用类型,而 "a" 和 "b" 的引用不同。

但是为什么第二个案例的结果是 "true" 呢?

我听说过 JVM 为了某些优化目的缓存-128到127之间的 int 值的对象。这样,"c" 和 "d" 的引用就相同了。

有人能给我更多关于这种行为的信息吗?我想了解这种优化的目的。在什么情况下会提高性能等。有关此问题的研究参考将非常好。


3
请注意,您不能编写依赖于此行为的代码,因为其他JVM / JDK实现者不必实现此优化,或者如果他们想要,他们可以扩展缓存值的范围。 - Behrang
5
请注意,缓存不适用于显式创建的对象。 即,Integer a = 1; Integer b = new Integer(1); System.out.println(a == b); // 输出 false - ccpizza
@ccpizza,显然它不适用于显式创建的对象,因为JLS保证在每次new操作符调用后分配并返回一个新的内存地址。 - Toni Nagy
2个回答

71

我想要了解这个优化的目的。它在哪些情况下会提高性能等相关问题。如果有关于这个问题的研究参考,那就太好了。

主要目的是为了节省内存,同样也由于更好的缓存效率而导致代码运行更快。

基本上,Integer类保留了一个范围为-128到127的Integer实例的缓存,所有的自动装箱、字面值和Integer.valueOf()的使用都将返回该范围的实例缓存。

这是基于这些小值比其他int值出现的频率要高得多的假设,因此避免为每个实例使用不同的对象的开销是有意义的(一个Integer对象大约占用12个字节)。


15
请注意,只有在使用自动装箱或静态方法Integer.valueOf()时,缓存才能起作用。调用构造函数将始终导致一个新的整数实例,即使该实例的值在-128到127范围内。 - Tim Bender
有人能解释一下这个现象吗?http://ideone.com/DAI75m- 为什么两个小于128的不同数值被声明为“不相等”?由于它们都被缓存,难道它们不应该属于同一个整数实例,因此"=="比较应该返回true,比较的是它们的引用吗? - David Doria
2
@David Doria:你似乎对“实例”有严重的误解。两个不同的值“属于同一个Integer实例”基本上是不可能的。对象实例基本上是内存中的一个区域。您可以拥有多个具有相同值的不同实例,但反过来不行。缓存将为不同的值返回不同的实例;它只是确保您始终获得相同值的实例。 - Michael Borgwardt
@MichaelBorgwardt,你能否提供一个缓存信息的来源?也许是JLS? - Olimpiu POP
@Michael:我还是不明白。如果整数使用8个字节来存储-128到+127的数字,用户可能会在某个时候用大于127的数字替换小数字。那么整数就必须将其存储在16位空间中。因此,整数始终需要保留8位空间和16位空间以存储原始int,对吗?那么内存如何被保存呢?在我看来,它们使用了更多的内存。或者我可能错过了什么? - Nav
我尽力用简单的话解释了这个现象。 - Zahid Khan

14

查看Integer.valueOf(int)的实现。对于小于256的输入,它将返回相同的Integer对象。

编辑:

如下所述,默认情况下实际上是-128+127


4
实际上,整型数的默认范围为 -128 <= i <= 127。似乎有一个系统属性(java.lang.Integer.IntegerCache.high)可以影响被缓存的整型数的最大值。 - Andreas
1
是的。抱歉,-128到+127之间。不过,重点是,小的i值被缓存了! - dty
更详细的答案请参考:https://dev59.com/vnA75IYBdhLWcg3wv7wj#64837154 - Zahid Khan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接