Sya*_*h K 59 java integer wrapper
Integer i = 3;
i = i + 1;
Integer j = i;
j = i + j;
Run Code Online (Sandbox Code Playgroud)
由于上面的示例代码中的语句创建了多少个对象,为什么?是否有任何IDE可以看到创建了多少对象(可能是在调试模式下)?
Bat*_*eba 101
令人惊讶的是,答案是零.
Integer-128到+127的所有s都是由JVM预先计算的.
您的代码创建对这些现有对象的引用.
Ste*_*n C 60
严格正确的答案是Integer创建的对象数量是不确定的.取决于,它可以在0到3之间,或256 1或甚至更多2之间
int值的其他代码在它之前运行4.Integer-128到127 的值不是严格要求预先计算的.实际上,指定Boxing转换的JLS 5.1.7说明了这一点:
如果被装箱的值p是-128和127之间的int类型的整数文字(§3.10.1)...那么让a和b成为p的任意两次装箱转换的结果.a == b总是如此.
有两点需要注意:
即使是javadoc for Integer.valueof(int)也没有指定结果是急切缓存的.
如果我们java.lang.Integer从Java 6到8 检查Java SE源代码,很明显当前的Java SE实现策略是预先计算值.但是,由于各种原因(见上文)仍然不足以让我们对"有多少对象"问题作出明确答复.
1 - 如果上述代码的执行Integer在Java版本中触发类初始化,则可能是256 ,其中在类初始化期间急切地初始化高速缓存.
2 - 如果缓存大于JVM规范要求,可能会更多.在某些Java版本中,可以通过JVM选项增加缓存大小.
3 - 除了平台实现装箱的一般方法之外,编译器还可以发现部分或全部计算可以在编译时完成或完全优化.
4 - 这样的代码可以触发整数缓存的惰性或急切初始化.
Den*_*ich 17
首先:你正在寻找的答案是0,正如其他人已经提到的那样.
但是让我们更深入一点.正如斯蒂芬所说,这取决于你执行它的时间.因为缓存实际上是懒惰的初始化.
如果你看一下java.lang.Integer.IntegerCache的文档:
缓存在首次使用时初始化.
这意味着如果它是您第一次调用实际创建的任何Integer:
从第二次调用它们,您创建0个对象.
一旦你把数字提高一点,事情会变得更加有趣.例如,通过以下示例:
Integer i = 1500;
Run Code Online (Sandbox Code Playgroud)
这里有效的选项是:0,1或1629到2147483776之间的任何数字(这次只计算创建的Integer值.为什么?答案在Integer-Cache定义的下一句中给出:
缓存的大小可以由-XX:AutoBoxCacheMax =选项控制.
所以你实际上可以改变实现的缓存的大小.
这意味着你可以达到以上线:
请记住:这只能在Oracle/Open JDK上保证(我检查了版本7和8)
正如您所看到的,完全正确的答案并不容易.但只是说0会让人开心.
PS:使用menthoned参数可以使以下语句成立: Integer.valueOf(1500) == 1500
编译器将Integer对象解包为ints以通过调用它们来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());
Run Code Online (Sandbox Code Playgroud)
赋值j = i;是一个完全正常的对象引用赋值,它不会创建新对象.它没有装箱或拆箱,也不需要因为Integer对象是不可变的.
valueOf允许该方法缓存对象,并且每次为特定数字返回相同的实例.它需要通过+127至-128整数缓存.对于起始编号i = 3,所有数字都很小并且保证要缓存,因此需要创建的对象数为0.严格来说,valueOf允许懒惰地缓存实例而不是将它们全部预先生成,因此该示例可能仍然是第一次创建对象,但如果在程序期间重复运行代码,则每次平均创建的对象数接近0 .
如果从较大的数字开始,其实例不会被缓存(例如,i = 300),该怎么办?然后每个valueOf调用必须创建一个新Integer对象,每次创建的对象总数为3.
(或者,也许它仍然为零,或者可能是数百万.请记住,编译器和虚拟机可以出于性能或实现原因重写代码,只要其行为没有以其他方式更改.所以它可以完全删除上面的代码,如果你不要使用结果.或者如果你尝试打印j,它可以意识到j在上面的片段之后总是会以相同的常量值结束,因此在编译时执行所有算术,并打印一个常量值.幕后操作代码的工作量总是一个实现细节.)