Java基元和原始包装器

时间:2013-08-29 05:03:14

标签: java garbage-collection heap-memory

我试图理解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()成本。

我是对的吗?

4 个答案:

答案 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仅计算一次。

来自JLS Section 15.26.2

  

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个整数实例