我试图理解Java原语和包装器是如何工作的。让我们考虑以下示例。
Integer sum = 0;
for(int i = 0; i < 10000; ++i) {
sum += i;
}
由于Integer是不可变的而且是非原始的,因此语句sum += i
将被编译为以下
sum = new Integer(sum.intValue() + i).
这将创建大约10000个Integer对象(每次调用new Integer
)以及将Integer解包为int的sum.intValue()
成本。
我是对的吗?
答案 0 :(得分:6)
不完全是。事实上:
sum += i;
相当于
sum = Integer.valueOf(sum.intValue() + i);
对于小整数值,Integer.valueOf(int)
将返回缓存的Integer
对象。这意味着您将创建少于10,000个新Integer
个对象。
但“小”通常意味着-128到+127(IIRC)......因此差异不大。
正如Louis Wasserman所指出的,对象分配很便宜,“年轻时死”的对象的垃圾收集甚至更便宜。尽管如此,你不应该不必要地使用原始包装器,特别是不能在这样的代码中使用。
答案 1 :(得分:2)
不,不是那样的。复合赋值运算符E1 op= E2
等同于E1 = (T) ((E1) op (E2))
,区别在于E1
仅计算一次。
E1 op = E2形式的复合赋值表达式等效于E1 =(T)((E1)op(E2)),其中T是E1的类型,但E1仅被评估一次。
因此,在整数引用和基本类型之间执行二进制运算。在这种情况下,整数引用将被取消装箱,并且将执行操作,并且值将再次装箱为Integer
引用。从JLS Section 5.6.2 - Binary Numeric Promotion开始:
如果任何操作数属于引用类型,则进行拆箱转换(第5.1.8节)。
因此,不一定不会创建新的Integer对象。循环中的表达式计算为:
Integer sum = Integer.valueOf(sum.intValue() + i);
valueOf
方法可能会使用Integer
对象的某些缓存值(对于某些范围)。
说了这么多,我希望你不是在原始代码中使用类似的包装类型,而只是为了理解目的。你不需要使用包装类型,除非你真的需要它,这种情况很少见。
答案 2 :(得分:2)
Prefer primitive types over Boxed types when using Loop
是的,你是正确的装箱和拆箱过程,特别是在循环中会严重妨碍性能。
但是在你的情况下,你只是在循环,你应该不在这里使用盒装基元,而是使用int
答案 3 :(得分:1)
是的,差不多10000.这是一个废弃的.class
Integer sum = Integer.valueOf(0);
for(int i = 0; i < 10000; i++)
sum = Integer.valueOf(sum.intValue() + i);
Integer.valueOf有一个小数字的缓存,默认为-128到127,所以实际上会创建10000 - 128个整数实例