使用Integer包装类创build了多less个对象?

Integer i = 3; i = i + 1; Integer j = i; j = i + j; 

上面示例代码中的语句的结果创build了多less个对象,为什么? 有什么IDE可以看到有多less对象被创build(可能在debugging模式)?

令人惊讶的是,答案是零。

所有从-128到+127的Integer都是由JVM预先计算的。

您的代码创build对这些现有对象的引用

严格正确的答案是创build的Integer对象的数量是不确定的 。 它可以在0到3之间,或者256 1或甚至更多2 ,取决于

  • Java平台3
  • 这是否是第一次执行此代码
  • (潜在地)依赖于装箱的int值的其他代码是否在它之前运行4

-128到127的Integer数值不是严格要求预先计算的 。 实际上,指定拳击转换的JLS 5.1.7这样说:

如果值为p的盒子是一个介于-128和127之间的整型文字(§3.10.1)…那么让a和b是p的任意两个装箱转换的结果。 总是这样,a == b。

有两件事要注意:

  • JLS只需要这个>>文字<<。
  • JLS并没有要求急切的caching值。 懒惰的caching也满足JLS的行为要求。

即使Integer.valueof(int)的javadoc也没有指定结果被急切地caching。

如果我们从Java 6到Java 8检查java.lang.Integer的Java SE源代码,那么显然目前的Java SE实现策略是预先计算这些值。 然而,由于各种原因(见上文),仍然不足以让我们对“多less个对象”问题给出明确的答案。


1 – 如果执行上面的代码,会在类初始化期间急切地初始化caching的Java版本中触发Integer类初始化。

2 – 如果caching大于JVM规范要求的话,可能会更多。 在某些版本的Java中,可以通过JVM选项增加caching大小。

3 – 除了平台实现装箱的一般方法外,编译器还可以发现部分或全部计算可以在编译时完成,也可以完全优化。

4 – 这样的代码可能触发整数caching的懒惰或急切的初始化。

首先:你正在寻找的答案是0 ,正如其他人已经提到的。

但是让我们再深入一点。 正如斯蒂芬所做的那样,取决于你执行的时间。 因为caching实际上是懒惰初始化的。

如果你看一下java.lang.Integer.IntegerCache的文档:

caching在第一次使用时被初始化。

这意味着,如果这是您第一次调用任何Integer,则实际创build:

  • 256个整数对象(或更多:见下文)
  • 1个数组存储整数的对象
  • 让我们忽略存储类(和方法/字段)所需的对象。 无论如何,它们都存储在元空间中。

从第二次你打电话给他们,你创build0个对象。


一旦你的数字更高一些,事情会变得更有趣。 例如通过以下示例:

 Integer i = 1500; 

这里有效的选项是:0,1或1629到2147483776之间的任何数字(这次只计算创build的Integer-values。为什么?答案在整数caching定义的下一句中给出:

caching的大小可以通过-XX:AutoBoxCacheMax =选项来控制。

所以你实际上可以改变实现的caching的大小。

这意味着你可以达到上面的线:

  • 1:如果您的caching小于1500,则为new Object
  • 0:新的对象,如果你的caching已经初始化,并包含1500
  • 1629:new(Integer) – 如果您的caching设置为1500,并且尚未初始化,则为对象。 然后,将创build从-128到1500的整数值。
  • 正如在上面的句子中,您可以在此得到任意数量的整数对象,直到:Integer.MAX_VALUE + 129,这是提到的:2147483776。

请记住:只有Oracle / Open JDK才能保证(我选中了版本7和版本8)

正如你所看到的,完全正确的答案并不是那么容易得到的。 但只是说0会让人开心。


PS:使用menthoned参数可以使以下语句为true: Integer.valueOf(1500) == 1500

编译器将Integer对象打包成int ,通过调用intValue()对它们进行算术运算,然后调用Integer.valueOfint结果赋值给Integervariables,所以你的例子等价于:

 Integer i = Integer.valueOf(3); i = Integer.valueOf(i.intValue() + 1); Integer j = i; j = Integer.valueOf(i.intValue() + j.intValue()); 

赋值j = i; 是一个完全正常的对象引用赋值,不会创build新的对象。 它没有装箱或取消装箱,也不需要像Integer对象是不可变的。

valueOf方法被允许caching对象并且每次返回一个特定的数字。 它需要cachingints -128到+127。 对于i = 3的起始数字,所有数字都很小,并保证被caching,所以需要创build的对象数量为0 。 严格地说, valueOf被允许caching实例,而不是全部预先生成,所以这个例子可能还是第一次创build对象,但是如果代码在程序中重复运行,那么平均每次创build的对象的数量0。

如果你从一个更大的数字开始,那么它的实例不会被caching(例如, i = 300 )呢? 然后每个valueOf调用都必须创build一个新的Integer对象,每次创build的对象总数是3

或者 ,也许它还是零,也可能是数百万,请记住,编译器和虚拟机可以重写代码,以达到性能或实现的原因,只要它的行为没有改变,那么它可以完全删除上面的代码不要使用结果,或者如果你尝试打印j ,可能会意识到j总是会在上面的代码片段后以相同的常量值结束,从而在编译时做所有的算术运算,并打印一个常量值。在后台执行代码的实际工作量始终是一个实现细节。)

您可以debuggingInteger.valueOf(int i)方法来自己找出它。 该方法由编译器的自动装箱过程调用。