Integer缓存

98 阅读1分钟

执行一段代码

public static void main(String[] args) throws IOException {
    Integer a = 127;
    Integer b = 127;
    System.out.println(a == b);
    Integer c = 128;
    Integer d = 128;
    System.out.println(c == d);
}

执行结果:

true
false

为什么会出现这种情况,使用javap -c查看字节码指令

public static void main(java.lang.String[]) throws java.io.IOException;
    Code:
       0: bipush        127
       2: invokestatic  #2                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
       5: astore_1
       6: bipush        127
       8: invokestatic  #2                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
      11: astore_2
      12: getstatic     #3                  // Field java/lang/System.out:Ljava/io/PrintStream;
      15: aload_1
      16: aload_2
      17: if_acmpne     24
      20: iconst_1
      21: goto          25
      24: iconst_0
      25: invokevirtual #4                  // Method java/io/PrintStream.println:(Z)V
      28: sipush        128
      31: invokestatic  #2                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
      34: astore_3
      35: sipush        128
      38: invokestatic  #2                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
      41: astore        4
      43: getstatic     #3                  // Field java/lang/System.out:Ljava/io/PrintStream;
      46: aload_3
      47: aload         4
      49: if_acmpne     56
      52: iconst_1
      53: goto          57
      56: iconst_0
      57: invokevirtual #4                  // Method java/io/PrintStream.println:(Z)V
      60: getstatic     #5                  // Field java/lang/System.in:Ljava/io/InputStream;
      63: invokevirtual #6                  // Method java/io/InputStream.read:()I
      66: pop
      67: return
}

从第2条和第8条、第31条和第38条指令可知,程序在使用a、b、c、d变量时,会使用Integer.valueOf()方法进行装箱,将基本数据类型包装成对应的引用类型。

3、查看Integer.valueOf()源码

public static Integer valueOf(int i) {
    if (i >= IntegerCache.low && i <= IntegerCache.high)
        return IntegerCache.cache[i + (-IntegerCache.low)];
    return new Integer(i);
}

由方法可知,当int数值范围在IntegerCache.low和IntegerCache.high之间时,返回的是cache数组元素,不在这个范围时,才会使用new新建一个对象返回。

继续分析IntegerCache,该类为Integer的静态内部类,内部定义了变量low为-128,high为127。定义cache数组,设置长度为(high - low) + 1,并且数组元素设为-128到127的Integer对象,该数组即为Integer缓存。

private static class IntegerCache {
    static final int low = -128;
    static final int high;
    static final Integer cache[];

    static {
        // high value may be configured by property
        int h = 127;
        String integerCacheHighPropValue =
            sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
        if (integerCacheHighPropValue != null) {
            try {
                int i = parseInt(integerCacheHighPropValue);
                i = Math.max(i, 127);
                // Maximum array size is Integer.MAX_VALUE
                h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
            } catch( NumberFormatException nfe) {
                // If the property cannot be parsed into an int, ignore it.
            }
        }
        high = h;

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

        // range [-128, 127] must be interned (JLS7 5.1.7)
        assert IntegerCache.high >= 127;
    }

    private IntegerCache() {}
}

因此,Integer内部缓存了-128到127的Integer对象,当使用valueOf方法包装int数值时,如果数值范围在-128到127之间,则直接返回缓存数组中的元素,引用地址一致,而数值范围不在-128到127之间,则创建新的对象,引用地址不一致。