使用Integer包装器类创建了多少个对象?

时间:2016-03-17 10:59:30

标签: java integer wrapper

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

上面的示例代码中的语句创建了多少个对象,为什么?是否有任何IDE可以看到创建了多少对象(可能是在调试模式下)?

5 个答案:

答案 0 :(得分:101)

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

JVM预先计算了从-128到+127的所有Integer

您的代码会为这些现有对象创建引用

答案 1 :(得分:60)

严格正确的答案是创建的Integer个对象的数量是不确定。它可能介于0和3之间,或256 1 或甚至更多 2 ,具体取决于

  • Java平台 3
  • 这是否是第一次执行此代码,
  • (可能)是否依赖于int拳击的其他代码在 4 之前运行。

-128到127的Integer值并非严格要求预先计算。事实上,指定拳击转换的JLS 5.1.7说明了这一点:

  

如果被装箱的值p是-128和127之间的int类型的整数文字(§3.10.1)...那么让a和b成为p的任意两次装箱转换的结果。 a == b总是如此。

有两点需要注意:

  • 只有
  • JLS不强制急切缓存值。延迟缓存也满足JLS的行为要求。

即使是Integer.valueof(int)的javadoc也没有指定,结果会被急切地缓存。

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

1 - 如果上述代码的执行在Java版本中触发Integer的类初始化,则可能为256,其中在类初始化期间急切地初始化缓存。

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

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

4 - 此类代码可能会触发整数缓存的延迟或急切初始化。

答案 2 :(得分:17)

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

但是让我们更进一步。正如斯蒂芬所说,这取决于你执行它的时间。因为缓存实际上是懒惰的初始化。

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

  

首次使用时初始化缓存。

这意味着如果这是您第一次调用实际创建的任何整数:

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

从第二次打电话给你,你创建了0个对象。

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

Integer i = 1500; 

此处的有效选项为:0,1或1629至2147483776之间的任何数字(此时仅计算创建的整数值。 为什么?答案在Integer-Cache定义的下一句中给出:

  

缓存的大小可以由-XX:AutoBoxCacheMax =选项控制。

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

这意味着你可以达到上面一行:

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

请记住:这只能在Oracle / Open JDK上保证(我检查了版本7和8)

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

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

答案 3 :(得分:5)

编译器将Integer个对象重新打包到int以通过调用intValue()对它们进行算术运算,然后调用Integer.valueOfint }结果将它们分配给Integer变量时,所以您的示例等同于:

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

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

允许valueOf方法缓存对象,并且每次为特定数字返回相同的实例。 必需来缓存整数-128到+127。对于您的起始编号i = 3,所有数字都很小并且保证会被缓存,因此需要创建的对象数量为 0 。严格来说,允许valueOf懒惰地缓存实例而不是将它们全部预先生成,因此该示例可能仍然是第一次创建对象,但如果在程序期间重复运行代码,则每个对象的数量都会创建时间平均接近0。

如果您从较大的数字开始,其实例不会被缓存(例如,i = 300),该怎么办?然后,每次valueOf调用都必须创建一个新的Integer对象,每次创建的对象总数 3

,也许它仍然为零,或者可能是数百万。请记住,编译器和虚拟机可以出于性能或实现原因重写代码,只要其行为没有以其他方式改变。因此,如果您不使用结果,它可以完全删除上述代码。或者如果您尝试打印j,它可能会意识到j将始终以在上面的代码片段之后的相同的常量值,因此在编译时执行所有算术,并打印一个常量值。在幕后运行代码的实际工作量总是一个实现细节。)

答案 4 :(得分:2)

您可以调试Integer.valueOf(int i)方法以自行查找。 编译器通过自动装箱过程调用此方法。