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

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预先计算的.

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

  • 有关如何访问这些现有对象的示例,请参阅[编写2 + 2 = 5的程序](http://codegolf.stackexchange.com/a/28818/15968)(你真的**不应该并操纵他们的漫画/灾难性的影响(你真的**不应该). (35认同)
  • @SyameshK https://docs.oracle.com/javase/7/docs/api/java/lang/Integer.html#valueOf(int)"此方法将始终缓存-128到127(包括端点)范围内的值,以及可以缓存此范围之外的其他值." (3认同)

Ste*_*n C 60

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

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

Integer-128到127 的值不是严格要求预先计算的.实际上,指定Boxing转换的JLS 5.1.7说明了这一点:

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

有两点需要注意:

  • JLS仅需要 >> literals <<.
  • JLS不强制要求对值进行急切缓存.延迟缓存也满足JLS的行为要求.

即使是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 - 这样的代码可以触发整数缓存的惰性或急切初始化.

  • 这不是完整的故事.这些`Integer`对象在`java.lang.Integer.IntegerCache`的类初始化程序中预先计算,但该类的初始化是由它的第一次使用触发的,所以除非JRE在输入`main`方法之前使用这样的盒装值(在我的测试中它没有),该范围内的第一个拳击将触发初始化.所以说没有创建"Integer"对象是不正确的,因为实际上在执行"main"方法时会创建256个"Integer"对象. (4认同)

Den*_*ich 17

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

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

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

缓存在首次使用时初始化.

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

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

从第二次调用它们,您创建0个对象.


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

Integer i = 1500; 
Run Code Online (Sandbox Code Playgroud)

这里有效的选项是:0,1或1629到2147483776之间的任何数字(这次只计算创建的Integer值.为什么?答案在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


Boa*_*ann 5

编译器将Integer对象解包为ints以通过调用它们来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());
Run Code Online (Sandbox Code Playgroud)

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

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

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

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