java中new Integer()和Integer.valueOf()效率比较

最近在公司参与一个项目,项目挺大,耗时一年左右,具体业务就不说了。。。
之后在项目开发将近结束时,公司用Coverity工具对整体代码进行了检视,结果发现了N多问题,好多都是自己不注意的细节,在感叹此工具的强大的同时,问了下项目经理这个工具的价格,告知,30万$ !!! 纳尼 神马!尼玛 代码检视这块儿和findbug也差不多啊, 这也忒狠了点吧。。。

不扯淡了,步入正题。
在检视过程中,提到如下一个问题,就是在我们代码中用new Integer(a) 的地方,好多都提示说Ineffective way, use Integer.valueOf(int) intead. 一时感觉好奇,翻开源码查看,没有查出啥究竟,然后后来利用debug模式进入源码调试才发现,原来里面的实现也大有天地。。。
首先查看valueof(int) 方法的实现:

Java代码 复制代码 收藏代码
  1. /**
  2. * Returns a <tt>Integer</tt> instance representing the specified
  3. * <tt>int</tt> value.
  4. * If a new <tt>Integer</tt> instance is not required, this method
  5. * should generally be used in preference to the constructor
  6. * {@link #Integer(int)}, as this method is likely to yield
  7. * significantly better space and time performance by caching
  8. * frequently requested values.
  9. *
  10. * @param i an <code>int</code> value.
  11. * @return a <tt>Integer</tt> instance representing <tt>i</tt>.
  12. * @since 1.5
  13. */
  14. public static Integer valueOf( int i) {
  15. if (i >= - 128 && i <= IntegerCache.high)
  16. return IntegerCache.cache[i + 128 ];
  17. else
  18. return new Integer(i);
  19. }
  /**
     * Returns a <tt>Integer</tt> instance representing the specified
     * <tt>int</tt> value.
     * If a new <tt>Integer</tt> instance is not required, this method
     * should generally be used in preference to the constructor
     * {@link #Integer(int)}, as this method is likely to yield
     * significantly better space and time performance by caching
     * frequently requested values.
     *
     * @param  i an <code>int</code> value.
     * @return a <tt>Integer</tt> instance representing <tt>i</tt>.
     * @since  1.5
     */
    public static Integer valueOf(int i) {
        if(i >= -128 && i <= IntegerCache.high)
            return IntegerCache.cache[i + 128];
        else
            return new Integer(i);
    }


注释里面说的很清楚,“如果一个Integer的实例不是必须的,那么此方法应该优先于构造器来使用。。。”
为什么呢?继续深入探究,进入IntegerCache类,这个是Integer类的一个内部私有类。

Java代码 复制代码 收藏代码
  1. private static class IntegerCache {
  2. static final int high;
  3. static final Integer cache[];
  4. static {
  5. final int low = - 128 ;
  6. // high value may be configured by property
  7. int h = 127 ;
  8. if (integerCacheHighPropValue != null ) {
  9. // Use Long.decode here to avoid invoking methods that
  10. // require Integer's autoboxing cache to be initialized
  11. int i = Long.decode(integerCacheHighPropValue).intValue();
  12. i = Math.max(i, 127 );
  13. // Maximum array size is Integer.MAX_VALUE
  14. h = Math.min(i, Integer.MAX_VALUE - -low);
  15. }
  16. high = h;
  17. cache = new Integer[(high - low) + 1 ];
  18. int j = low;
  19. for ( int k = 0 ; k < cache.length; k++)
  20. cache[k] = new Integer(j++);
  21. }
  22. private IntegerCache() {}
  23. }
 private static class IntegerCache {
        static final int high;
        static final Integer cache[];

        static {
            final int low = -128;

            // high value may be configured by property
            int h = 127;
            if (integerCacheHighPropValue != null) {
                // Use Long.decode here to avoid invoking methods that
                // require Integer's autoboxing cache to be initialized
                int i = Long.decode(integerCacheHighPropValue).intValue();
                i = Math.max(i, 127);
                // Maximum array size is Integer.MAX_VALUE
                h = Math.min(i, Integer.MAX_VALUE - -low);
            }
            high = h;

            cache = new Integer[(high - low) + 1];
            int j = low;
            for(int k = 0; k < cache.length; k++)
                cache[k] = new Integer(j++);
        }

        private IntegerCache() {}
    }


至此,谜底基本解开,原来IntegerCache相当于做了一个缓存,在第一次被调用时,首先初始化生成了从-128到127共256个对象的数组,在以后凡是在这个范围内的int值都可以直接从此缓存中取,而不在再次生成Integer对象,大大提高了对象的利用率。

然后我做了一个测试类,来测试二者真正的效率区别:

Java代码 复制代码 收藏代码
  1. public static void testEfficiency(){
  2. int count = 10000000 ;
  3. long t1 = System.currentTimeMillis();
  4. for ( int i = 0 ; i < count; i ++){
  5. int a = new Integer(i% 128 *(i% 2 == 0 ?- 1 : 1 ));
  6. }
  7. long t2 = System.currentTimeMillis();
  8. for ( int i = 0 ; i < count; i ++){
  9. int b = Integer.valueOf(i% 128 *(i% 2 == 0 ?- 1 : 1 ));
  10. }
  11. long t3 = System.currentTimeMillis();
  12. System.out.println("Time of new Integer() method:" +(t2-t1)+ "ms" );
  13. System.out.println("Time of Integer.ValueOf:" +(t3-t2)+ "ms" );
  14. }
	public static void testEfficiency(){
		int count = 10000000;
		long t1 = System.currentTimeMillis();
		for(int i = 0; i < count; i ++){

			int a = new Integer(i%128 *(i%2 == 0?-1:1));
			
		}
		long t2 = System.currentTimeMillis();
		for(int i = 0; i < count; i ++){
			int b = Integer.valueOf(i%128 *(i%2 == 0?-1:1));
		}
		long t3 = System.currentTimeMillis();
		System.out.println("Time of new Integer() method:"+(t2-t1)+"ms");
		System.out.println("Time of Integer.ValueOf:"+(t3-t2)+"ms");
	}


输出结果:

Java代码 复制代码 收藏代码
  1. Time of new Integer() method:125ms
  2. Time of Integer.ValueOf:94ms
Time of new Integer() method:125ms
Time of Integer.ValueOf:94ms


二者似乎区别多大,不过这说明JDK虚拟机的效率比较高,
然后将这两种方式单独封装到两个方法中,利用两个程序进行调试,然后再看下javaw.exe所占的内存,区别就出来了。。。大家可以自己试一下,为了查看内存,可以将程序sleep 20s来查看, 我本机的测试结果:
new Integer方式:13 516K
Integer.valueOf方式:8 852K.
相差4664K.

实验基本到此结束,但是学习却只是一个开始,在实际项目中也可以参考此种实现方式,懒加载和缓存的思想。

转自:http://feikiss.iteye.com/blog/1285283

猜你喜欢

转载自woshixushigang.iteye.com/blog/1379138