关于使用new Integer还是Integer.valueOf的研究

本文深入探讨了Java中使用Integer.valueOf代替new Integer的优化策略,通过剖析Integer源码,揭示了其内部缓存机制如何提高性能。文章还展示了通过字节码研究来验证这一优化的有效性,并对比了不同初始化方式对程序运行的影响,最终得出结论:合理利用缓存可以显著提升程序效率。

作者:fbysss
msn:jameslastchina@hotmail.com  
blog:blog.youkuaiyun.com/fbysss
声明:本文由fbysss原创,转载请注明出处

前言:

最近看到这样的说法:使用Integer.valueOf代替new Integer更有效率,原因是研究了Integer源码,发现有一个缓存可以利用。

对此我也一探究竟。发现这其实与Java的自动装箱拆箱有关,直接使用Integer i =数值的方式即可。

通过字节码研究是比较有效的方式。那我们来看看吧:


-------------------
Integer.valueOf源码:
-------------------


   public static Integer valueOf(int i) {
final int offset = 128;
if (i >= -128 && i <= 127) { // must cache 
    return IntegerCache.cache[i + offset];
}
        return new Integer(i);
    }


-------------------
IntegerCache 源码(jdk1.6.0_12):
-------------------
    private static class IntegerCache {
private IntegerCache(){}


static final Integer cache[] = new Integer[-(-128) + 127 + 1];//注意这个cache是final的


static {
    for(int i = 0; i < cache.length; i++)
cache[i] = new Integer(i - 128);
}



源码1:

public class TestInt {


/**
* @param args
*/
public static void main(String[] args) {
int i =200;
i ++;
}
}
---------------------
javap -c TestInt
---------------------
public class com.sss.newage.test.TestInt extends java.lang.Object{
public com.sss.newage.test.TestInt();
  Code:
   0:   aload_0
   1:   invokespecial   #8; //Method java/lang/Object."<init>":()V
   4:   return


public static void main(java.lang.String[]);
  Code:
   0:   sipush  200
   3:   istore_1
   4:   iinc    1, 1
   7:   return


}



源码2:
public class TestInt {


/**
* @param args
*/
public static void main(String[] args) {
Integer i =200;
i ++;
}
}
---------------------
javap -c TestInt
---------------------
public class com.sss.newage.test.TestInt extends java.lang.Object{
public com.sss.newage.test.TestInt();
  Code:
   0:   aload_0
   1:   invokespecial   #8; //Method java/lang/Object."<init>":()V
   4:   return


public static void main(java.lang.String[]);
  Code:
   0:   sipush  200
   3:   invokestatic    #16; //Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
   6:   astore_1
   7:   aload_1
   8:   invokevirtual   #22; //Method java/lang/Integer.intValue:()I
   11:  iconst_1
   12:  iadd
   13:  invokestatic    #16; //Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
   16:  astore_1
   17:  return


}

我们可以看到:

1.第3行(行标为3)调用了Integer.valueOf,一旦数字在缓存窗口中,则能够提高效率,那么我们可以认为,缓存不用白不用,的确比new Integer要好。

2..第8行(行标为8)进行了自动拆箱(intValue),目的是进行数字的加1运算

3.注意第13行,运算完毕之后,再次进行装箱(valueOf),这些运算都不影响cache本身,所以cache设计成只读即可,也不存在线程安全问题。



源码3:修改Integer i =200;为Integer i =Integer.valueOf(200);
public class TestInt {


/**
* @param args
*/
public static void main(String[] args) {
Integer i =Integer.valueOf(200);
i ++;
}
}


public class com.sss.newage.test.TestInt extends java.lang.Object{
public com.sss.newage.test.TestInt();
  Code:
   0:   aload_0
   1:   invokespecial   #8; //Method java/lang/Object."<init>":()V
   4:   return


public static void main(java.lang.String[]);
  Code:
   0:   sipush  200
   3:   invokestatic    #16; //Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
   6:   astore_1
   7:   aload_1
   8:   invokevirtual   #22; //Method java/lang/Integer.intValue:()I
   11:  iconst_1
   12:  iadd
   13:  invokestatic    #16; //Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
   16:  astore_1
   17:  return


}

可以看到,使用Integer i = 200;与Integer i = Integer.valueOf(200);是等价的,从程序员读写习惯来看,使用Integer i = 200;的形式更好




------------------------

注意一点:

------------------------

最新版本的Jdk,Integer有改写,IntegerCache 的缓存窗口可以配置(通过JVM参数 -XX:AutoBoxCacheMax设置)。

JDK1.6.0_27相关源码

 /**
     * Cache to support the object identity semantics of autoboxing for values between 
     * -128 and 127 (inclusive) as required by JLS.
     *
     * The cache is initialized on first usage. During VM initialization the
     * getAndRemoveCacheProperties method may be used to get and remove any system
     * properites that configure the cache size. At this time, the size of the
     * cache may be controlled by the vm option -XX:AutoBoxCacheMax=<size>.
     */


    // value of java.lang.Integer.IntegerCache.high property (obtained during VM init)

    static void getAndRemoveCacheProperties() {
        if (!sun.misc.VM.isBooted()) {
            Properties props = System.getProperties();
            integerCacheHighPropValue =
                (String)props.remove("java.lang.Integer.IntegerCache.high");
            if (integerCacheHighPropValue != null)
                System.setProperties(props);  // remove from system props
        }
    }


    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() {}
    }

本文编写时间仓促,若有描述不妥或论证有问题的地方,欢迎各位交流、指正。

### 代码含义 - `Integer n = new Integer(2);`:使用 `new` 关键字创建一个 `Integer` 对象,该对象在堆内存中分配独立的空间,存储的值为 `2`。这是显式地在堆上创建一个新的 `Integer` 对象实例。 - `Integer d = Integer.valueOf(244);`:调用 `Integer` 类的静态方法 `valueOf` 来创建一个 `Integer` 对象。`valueOf` 方法会根据传入的参数值的范围进行不同的处理。对于值在 `-128` 到 `127` 之间的整数,会从 `Integer` 类的缓存中获取已存在的对象;对于不在这个范围内的值,则会创建一个新的 `Integer` 对象。由于 `244` 不在 `-128` 到 `127` 范围内,所以会创建一个新的 `Integer` 对象存储 `244` [^3]。 ### 代码区别 - **创建方式**:`new Integer(2)` 是通过构造函数直接在堆上创建新对象,每次使用都会创建一个新的实例;而 `Integer.valueOf(244)` 会先检查值是否在 `-128` 到 `127` 范围内,若在则使用缓存中的对象,不在则创建新对象 [^2][^3]。 - **性能和内存占用**:频繁使用 `new Integer()` 会创建大量新对象,增加内存开销;而 `Integer.valueOf()` 对于常用范围内的值复用缓存对象,能节省内存和提高性能 [^3]。 - **比较结果**:使用 `==` 比较时,两个 `new Integer()` 创建的对象即使值相同,比较结果也为 `false`,因为它们是不同的对象实例;而 `Integer.valueOf()` 创建的对象,若值在 `-128` 到 `127` 范围内,相同值的对象比较结果为 `true`,不在此范围则和 `new Integer()` 情况相同 [^4]。 ### 相关知识 在 Java 中,对于基本数据类型 `int` 和其包装类 `Integer`,有自动装箱和拆箱机制。自动装箱是将 `int` 类型的值自动转换为 `Integer` 对象,例如 `Integer a = 10;` 实际上等价于 `Integer a = Integer.valueOf(10);`;自动拆箱则是将 `Integer` 对象转换为 `int` 类型,例如 `int b = a;`。 以下是示例代码: ```java public class Main { public static void main(String[] args) { Integer n = new Integer(2); Integer d = Integer.valueOf(244); Integer e = Integer.valueOf(2); // 比较 new IntegerInteger.valueOf System.out.println(n == e); // false,不同对象实例 // 自动装箱示例 Integer f = 10; // 自动拆箱示例 int g = f; } } ```
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值