Java原语和原语包装器

Java原语和原语包装器,java,garbage-collection,heap-memory,Java,Garbage Collection,Heap Memory,我试图理解Java原语和包装器是如何工作的。让我们考虑下面的例子。 Integer sum = 0; for(int i = 0; i < 10000; ++i) { sum += i; } 这将创建大约10000个整数对象(每次调用newInteger)以及将整数解包为int的sum.intValue()成本 我说得对吗?不,不是那样的。复合赋值运算符E1 op=E2相当于E1=(T)((E1)op(E2)),不同之处在于E1只计算一次 发件人: 形式为E1 op=E2的复合赋

我试图理解Java原语和包装器是如何工作的。让我们考虑下面的例子。

Integer sum = 0;
for(int i = 0; i < 10000; ++i) {
    sum += i;
}
这将创建大约10000个整数对象(每次调用new
Integer
)以及将整数解包为int的
sum.intValue()
成本


我说得对吗?

不,不是那样的。复合赋值运算符
E1 op=E2
相当于
E1=(T)((E1)op(E2))
,不同之处在于
E1
只计算一次

发件人:

形式为E1 op=E2的复合赋值表达式等价于E1=(T)((E1)op(E2)),其中T是E1的类型,但E1仅计算一次

因此,在整数引用和基元类型之间执行二进制操作。在这种情况下,整数引用将被取消装箱,并执行操作,值将再次装箱到
Integer
reference。自:

如果任何操作数是引用类型,则它将进行取消装箱转换(§5.1.8)

因此,不需要创建新的整数对象。循环中的表达式计算为:

Integer sum = Integer.valueOf(sum.intValue() + i);
方法的
valueOf
可以使用
Integer
对象的一些缓存值(对于某些范围)


说到这里,我希望您不是在原始代码中使用这样的包装器类型,而是为了理解目的。您不需要使用包装器类型,除非您真的需要它,而且这种情况很少见。

不完全如此。事实上:

    sum += i;
相当于

    sum = Integer.valueOf(sum.intValue() + i);
对于小的整数值,
integer.valueOf(int)
将返回一个缓存的
integer
对象。这意味着您将创建不到10000个新的
Integer
对象

但“小”通常意味着-128到+127(IIRC)。。。所以差别不会很大


正如Louis Wasserman所指出的,对象分配是廉价的,而对“早死”对象的垃圾收集则更便宜。然而,您不应该不必要地使用基本包装,尤其是在这样的代码中。

是的,您是正确的装箱和拆箱过程,特别是在循环中,会严重影响性能


但在您的情况下,您只是在循环,您不应该在这里使用装箱原语,而是使用
int
是的,几乎10000。这是一门脱衣舞课

    Integer sum = Integer.valueOf(0);
    for(int i = 0; i < 10000; i++)
        sum = Integer.valueOf(sum.intValue() + i);
Integer sum=Integer.valueOf(0);
对于(int i=0;i<10000;i++)
sum=整数.valueOf(sum.intValue()+i);

Integer.valueOf有一个用于小数字的缓存,默认为-128到127,因此实际上将创建10000到128个整数实例

问题是什么?为什么这里需要一个包装类,不必要的取消装箱开销,请阅读:@sanbhat问题是关于盒装原语的效率和内存消耗。实际上它不是
newinteger(int)
,而是
Integer.valueOf(int)
。后一个函数有一个缓存。如果找不到,则使用构造函数。对,但仍然不需要在共享代码中使用包装类。取消装箱和自动装箱的不必要开销。确实如此,但在这种循环的情况下,不会有很多缓存对象,并且会创建新的对象。我说的对吗?对。请注意,物品(尤其是快速丢弃的物品)很便宜,但确实如此。
    Integer sum = Integer.valueOf(0);
    for(int i = 0; i < 10000; i++)
        sum = Integer.valueOf(sum.intValue() + i);