Integer i = 3;
i = i + 1;
Integer j = i;
j = i + j;
上面的示例代码中的语句创建了多少个对象,为什么?是否有任何IDE可以看到创建了多少对象(可能是在调试模式下)?
答案 0 :(得分:101)
令人惊讶的是,答案是零。
JVM预先计算了从-128到+127的所有Integer
。
您的代码会为这些现有对象创建引用。
答案 1 :(得分:60)
严格正确的答案是创建的Integer
个对象的数量是不确定。它可能介于0和3之间,或256 1 或甚至更多 2 ,具体取决于
int
拳击的其他代码在 4 之前运行。 -128到127的Integer
值并非严格要求预先计算。事实上,指定拳击转换的JLS 5.1.7说明了这一点:
如果被装箱的值p是-128和127之间的int类型的整数文字(§3.10.1)...那么让a和b成为p的任意两次装箱转换的结果。 a == b总是如此。
有两点需要注意:
即使是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的文档:
首次使用时初始化缓存。
这意味着如果这是您第一次调用实际创建的任何整数:
从第二次打电话给你,你创建了0个对象。
一旦你把数字提高一点,事情会变得更加有趣。例如。通过以下示例:
Integer i = 1500;
此处的有效选项为:0,1或1629至2147483776之间的任何数字(此时仅计算创建的整数值。 为什么?答案在Integer-Cache定义的下一句中给出:
缓存的大小可以由-XX:AutoBoxCacheMax =选项控制。
所以你实际上可以改变实现的缓存大小。
这意味着你可以达到上面一行:
请记住:这只能在Oracle / Open JDK上保证(我检查了版本7和8)
正如您所看到的,完全正确的答案并不容易。但只是说0
会让人开心。
PS:使用menthoned参数可以使以下语句成立:Integer.valueOf(1500) == 1500
答案 3 :(得分:5)
编译器将Integer
个对象重新打包到int
以通过调用intValue()
对它们进行算术运算,然后调用Integer.valueOf
来int
}结果将它们分配给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)方法以自行查找。 编译器通过自动装箱过程调用此方法。