Java中的自动装箱与手动装箱

And*_*i N 21 java autoboxing

为什么第二段代码更快?

Map<Integer, Double> map = new HashMap<Integer, Double>();
for (int i = 0; i < 50000; i++) {
    for (double j = 0.0; j < 10000; j++) {
        map.put(i, j);
    }
}

Map<Integer, Double> map=new HashMap<Integer, Double>();
for (int i = 0; i < 50000; i++) {
    for (double j = 0.0; j < 10000; j++) {            
        map.put(new Integer(i), new Double(j));
    }
}
Run Code Online (Sandbox Code Playgroud)

Esk*_*ola 48

Autoboxing使用Integer.valueOf,内部缓存小整数的Integer对象(默认为-128到127,但最大值可以使用"java.lang.Integer.IntegerCache.high"属性配置 - 请参阅Integer.valueOf的源代码) ,所以它与new Integer直接呼叫不同.因为Integer.valueOf在调用之前会快速检查整数值的大小new Integer,所以new Integer直接调用它会快一点(尽管如果你有很多小整数它会使用更多的内存).Java中的分配非常快,并且执行GC的时间与活动短期对象的数量成比例(即与垃圾量不成比例),因此GC也非常快.

但是根据JVM版本和启用了哪些优化,存在标量替换优化,这可以在分配短期对象时产生更大的性能差异(在您的示例中,无法进行优化,因为您正在存储地图中的对象,但在许多其他情况下它很有用).

在最近的JVM版本中,存在标量替换优化(除了在1.6.0_18中暂时禁用转义分析),这意味着可以优化短期对象的分配.当JVM中的标量替换是新的时,有人制作了一个基准,其中有与您类似的代码.结果是使用基元的代码最快,具有显式new Integer()调用的代码几乎与使用基元的代码一样快,并且使用自动装箱的代码要慢得多.这是因为自动装箱使用Integer.valueOf并且至少当时的标量替换优化没有考虑到这种特殊情况.我不知道从那时起优化是否得到了改进.

  • 他的意思是它检查传递给它的int值,看它是否在缓存的值范围内. (4认同)

Tom*_*ine 14

Autoboxing将使用Integer.valueOfDouble.valueOf.调用这些方法有一些开销(尽管它最终会被内联).还有Integer.valueOf一些检查低值以使用池化实例,这在您的代码中通常不会获胜(尽管它可以减少堆大小).池化实例可能是一个胜利,它们可以减少堆大小,GC时间,甚至可以提高相等测试性能.

但是,总的来说,这是一种微观优化,你通常应该忽略它.


小智 7

因为微基准测试的结果不可靠?

此外,自动装箱是使用Integer.valueOf()和Double.valueOf()完成的,而不是构造函数.