使用 Integer 包装器 class 创建了多少个对象?
How many objects are created by using the Integer wrapper class?
Integer i = 3;
i = i + 1;
Integer j = i;
j = i + j;
上面示例代码中的语句创建了多少个对象?为什么?有没有 IDE 我们可以看到创建了多少对象(也许在调试模式下)?
大家可以调试Integer.valueOf(int i)方法自行查找。
此方法由编译器的自动装箱过程调用。
令人惊讶的是,答案是零。
从-128到+127的所有Integer
都是JVM预先计算的。
您的代码创建了对这些现有对象的引用。
严格正确的答案是创建的 Integer
个对象的数量 不确定 。它可能介于 0 和 3 之间,或者 2561 甚至更多2,具体取决于
- Java平台3,
- 这是否是第一次执行此代码,并且
- (可能)其他依赖
int
值装箱的代码是否在它之前运行4.
-128 到 127 的 Integer
值并不严格要求预先计算。事实上,指定 Boxing 转换的 JLS 5.1.7 是这样说的:
If the value p being boxed is an integer literal of type int between -128 and 127 inclusive (§3.10.1) ... then let a and b be the results of any two boxing conversions of p. It is always the case that a == b.
需要注意两点:
- 仅 JLS 需要 >>文字<<。
- JLS 不强制渴望 缓存值。惰性缓存也满足了 JLS 的行为要求。
甚至 Integer.valueof(int)
的 javadoc 也没有指定 急切地缓存结果。
如果我们从 Java 6 到 8 检查 java.lang.Integer
的 Java SE 源代码,很明显当前的 Java SE 实现策略是预先计算价值。但是,由于各种原因(见上文),这仍然不足以让我们对 "how many objects" 问题给出明确的答案。
1 - 如果上述代码的执行触发 class 初始化 Integer
在缓存被急切初始化的 Java 版本中,则可能是 256在 class 初始化期间。
2 - 如果缓存大于 JVM 规范要求,它可能会更多。在 Java.
的某些版本中,可以通过 JVM 选项增加缓存大小
3 - 除了平台实现装箱的一般方法外,编译器可以发现部分或全部计算可以在编译时完成或完全优化。
4 - 这样的代码可能会触发整数缓存的延迟或急切初始化。
首先:您正在寻找的答案是 0
,正如其他人已经提到的那样。
但让我们更深入一点。正如斯蒂芬提到的,这取决于你执行它的时间。因为缓存实际上是惰性初始化的。
如果你查看 java.lang.Integer.IntegerCache 的文档:
The cache is initialized on first usage.
这意味着如果这是您第一次调用您实际创建的任何 Integer:
- 256 个整数对象(或更多:见下文)
- 1 个用于存储整数的数组对象
- 让我们忽略存储 Class(和方法/字段)所需的对象。它们无论如何都存储在元空间中。
从第二次调用它们开始,您创建了 0 个对象。
一旦你把数字调高一点,事情就会变得更有趣。例如。通过以下示例:
Integer i = 1500;
这里的有效选项是:0、1 或 1629 到 2147483776 之间的任何数字(这次只计算创建的整数值。
为什么? Integer-Cache定义的下一句给出了答案:
The size of the cache may be controlled by the -XX:AutoBoxCacheMax= option.
所以你实际上可以改变实现的缓存的大小。
这意味着您可以到达上面的行:
- 1: 如果您的缓存小于 1500,则为新对象
- 0: new Objects 如果你的缓存之前已经初始化并且包含 1500
- 1629: new (Integer) - 如果您的缓存设置为恰好 1500 且尚未初始化的对象。然后将创建从 -128 到 1500 的整数值。
- 就像上面的句子一样,你在这里达到了任意数量的整数对象:Integer.MAX_VALUE + 129,也就是提到的:2147483776。
请记住:这仅在 Oracle / Open 上得到保证JDK(我检查了版本 7 和 8)
如您所见,要获得完全正确的答案并不容易。但是只要说0
就会让人开心
PS:使用menthoned参数可以使下面的语句为真:Integer.valueOf(1500) == 1500
编译器将 Integer
对象拆箱到 int
中,通过调用 intValue()
on them, and it calls Integer.valueOf
将 int
结果分配给 [=] 进行算术计算11=] 变量,所以你的例子相当于:
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
方法缓存对象,并且return每次为特定数字缓存相同的实例。 需要 缓存 −128 到 +127 的整数。对于你的起始数i = 3
,所有的数都是小的,保证缓存,所以需要创建的对象数是0。严格来说,valueOf
允许延迟缓存实例而不是让它们全部预先生成,因此该示例可能仍会在第一次创建对象,但如果代码在程序中重复 运行每次 平均 接近 0 时创建的对象数。
如果您从一个较大的数字开始,其实例将不会被缓存(例如,i = 300
)怎么办?那么每次valueOf
调用必须创建一个新的Integer
对象,每次创建的对象总数为3.
(或,也许它仍然是零,也许它是数百万。请记住,出于性能或实现原因,允许编译器和虚拟机重写代码,只要其行为没有其他改变。所以如果你不使用结果,它可以完全删除上面的代码。或者如果你尝试打印j
,它可以意识到j
在上面的代码片段之后总是以相同的常量值结束,因此在编译时进行所有算术运算,并打印一个常量值。在幕后完成的实际工作量 运行 你的代码始终是实现细节。)
Integer i = 3;
i = i + 1;
Integer j = i;
j = i + j;
上面示例代码中的语句创建了多少个对象?为什么?有没有 IDE 我们可以看到创建了多少对象(也许在调试模式下)?
大家可以调试Integer.valueOf(int i)方法自行查找。 此方法由编译器的自动装箱过程调用。
令人惊讶的是,答案是零。
从-128到+127的所有Integer
都是JVM预先计算的。
您的代码创建了对这些现有对象的引用。
严格正确的答案是创建的 Integer
个对象的数量 不确定 。它可能介于 0 和 3 之间,或者 2561 甚至更多2,具体取决于
- Java平台3,
- 这是否是第一次执行此代码,并且
- (可能)其他依赖
int
值装箱的代码是否在它之前运行4.
-128 到 127 的 Integer
值并不严格要求预先计算。事实上,指定 Boxing 转换的 JLS 5.1.7 是这样说的:
If the value p being boxed is an integer literal of type int between -128 and 127 inclusive (§3.10.1) ... then let a and b be the results of any two boxing conversions of p. It is always the case that a == b.
需要注意两点:
- 仅 JLS 需要 >>文字<<。
- JLS 不强制渴望 缓存值。惰性缓存也满足了 JLS 的行为要求。
甚至 Integer.valueof(int)
的 javadoc 也没有指定 急切地缓存结果。
如果我们从 Java 6 到 8 检查 java.lang.Integer
的 Java SE 源代码,很明显当前的 Java SE 实现策略是预先计算价值。但是,由于各种原因(见上文),这仍然不足以让我们对 "how many objects" 问题给出明确的答案。
1 - 如果上述代码的执行触发 class 初始化 Integer
在缓存被急切初始化的 Java 版本中,则可能是 256在 class 初始化期间。
2 - 如果缓存大于 JVM 规范要求,它可能会更多。在 Java.
的某些版本中,可以通过 JVM 选项增加缓存大小3 - 除了平台实现装箱的一般方法外,编译器可以发现部分或全部计算可以在编译时完成或完全优化。
4 - 这样的代码可能会触发整数缓存的延迟或急切初始化。
首先:您正在寻找的答案是 0
,正如其他人已经提到的那样。
但让我们更深入一点。正如斯蒂芬提到的,这取决于你执行它的时间。因为缓存实际上是惰性初始化的。
如果你查看 java.lang.Integer.IntegerCache 的文档:
The cache is initialized on first usage.
这意味着如果这是您第一次调用您实际创建的任何 Integer:
- 256 个整数对象(或更多:见下文)
- 1 个用于存储整数的数组对象
- 让我们忽略存储 Class(和方法/字段)所需的对象。它们无论如何都存储在元空间中。
从第二次调用它们开始,您创建了 0 个对象。
一旦你把数字调高一点,事情就会变得更有趣。例如。通过以下示例:
Integer i = 1500;
这里的有效选项是:0、1 或 1629 到 2147483776 之间的任何数字(这次只计算创建的整数值。 为什么? Integer-Cache定义的下一句给出了答案:
The size of the cache may be controlled by the -XX:AutoBoxCacheMax= option.
所以你实际上可以改变实现的缓存的大小。
这意味着您可以到达上面的行:
- 1: 如果您的缓存小于 1500,则为新对象
- 0: new Objects 如果你的缓存之前已经初始化并且包含 1500
- 1629: new (Integer) - 如果您的缓存设置为恰好 1500 且尚未初始化的对象。然后将创建从 -128 到 1500 的整数值。
- 就像上面的句子一样,你在这里达到了任意数量的整数对象:Integer.MAX_VALUE + 129,也就是提到的:2147483776。
请记住:这仅在 Oracle / Open 上得到保证JDK(我检查了版本 7 和 8)
如您所见,要获得完全正确的答案并不容易。但是只要说0
就会让人开心
PS:使用menthoned参数可以使下面的语句为真:Integer.valueOf(1500) == 1500
编译器将 Integer
对象拆箱到 int
中,通过调用 intValue()
on them, and it calls Integer.valueOf
将 int
结果分配给 [=] 进行算术计算11=] 变量,所以你的例子相当于:
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
方法缓存对象,并且return每次为特定数字缓存相同的实例。 需要 缓存 −128 到 +127 的整数。对于你的起始数i = 3
,所有的数都是小的,保证缓存,所以需要创建的对象数是0。严格来说,valueOf
允许延迟缓存实例而不是让它们全部预先生成,因此该示例可能仍会在第一次创建对象,但如果代码在程序中重复 运行每次 平均 接近 0 时创建的对象数。
如果您从一个较大的数字开始,其实例将不会被缓存(例如,i = 300
)怎么办?那么每次valueOf
调用必须创建一个新的Integer
对象,每次创建的对象总数为3.
(或,也许它仍然是零,也许它是数百万。请记住,出于性能或实现原因,允许编译器和虚拟机重写代码,只要其行为没有其他改变。所以如果你不使用结果,它可以完全删除上面的代码。或者如果你尝试打印j
,它可以意识到j
在上面的代码片段之后总是以相同的常量值结束,因此在编译时进行所有算术运算,并打印一个常量值。在幕后完成的实际工作量 运行 你的代码始终是实现细节。)