effective java item6 避免创建不必要的对象

在《effective java》中‘避免创建不必要的对象’一节,有如下代码

private static long sum() {
       Long sum = 0L;
       for (long i = 0; i <= Integer.MAX_VALUE; i++)
           sum += i;
return sum; }

This program gets the right answer, but it is much slower than it should be, due to a one-character typographical error. The variable sum is declared as a Long instead of a long, which means that the program constructs about 231 unnecessary Long instances (roughly one for each time the long i is added to the Long sum).
为什么把sum设置成Long对象,会在每一次循环的时候创建Long实例?

阅读 2.2k
3 个回答

0,不知道这本书的 序言 你看了没有,若你看了就应该知道它不适合初学者,否则你也不会有这样的问题了
1,对于你所提的问题,像这样直接给包装类型赋值,jvm在执行时相当于调用该包装类的valueof方法,对于Long的valueof方法java.lang.Long#valueOf(long),如果i不在long cache 中,那么就new Long(i) 一个新对象,显然上述代码中,在sum几次遍历后大于127就会创建新的实例,至于为什么有long cache,你可以理解为帮机器节省内存(毕竟这些类上世纪就已经设计出来了,那时的机器内存可没有现在这么多)

interesting !
自动装箱和拆箱是jdk1.5的新特性。
jdk1.5之前,两个Integer对象是不能直接相加的。
例如

Integer a=new Integer(10);
Integer b=new Integer(20);
int a1=a.intValue();
int b1=b.intValue();
int sum=a1+b1;

需要先调用intValue()方法转化成int,才能实现10+20;

jdk1.5之后,就不需要自己转化intValue()这一步,jvm帮我们做了‘拆箱’。

再讲一下‘装箱’:例如Long l=100L,赋值操作实际上调用了Long的valueOf方法。

   public static Long valueOf(long l) {
        final int offset = 128;
        if (l >= -128 && l <= 127) { // will cache
            return LongCache.cache[(int)l + offset];
        }
        return new Long(l);
    }

------------再回到我们的问题上---------------

for (long i = 0; i <= Integer.MAX_VALUE; i++)
           sum += i;

每一次循环包括一次相加运算(拆箱)和赋值操作(装箱)
而由valueOf的源码可知,当数值小于128的时候,valueOf方法返回同一对象;当大于127的时候,valueOf方法是返回了新的Long对象
共计(2的31次方-128)次,几乎等于每一次循环都新创建了一个Long对象,

新手上路,请多包涵

包装类型的+操作是个语法糖,背后会进行拆箱和装箱的操作

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题