使用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.valueOf
将int
结果赋值给Integer
variables,所以你的例子等价于:
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)方法来自己找出它。 该方法由编译器的自动装箱过程调用。