天天看點

關于Java中Integer對象緩存問題的分析

Android

Surface

看的有點頭暈,換個口味,下一篇再更

偶然網上看到如下代碼:

public class IntegerTest {
    private Integer a = 100;
    private Integer b = 100;
    private Integer c = 200;
    private Integer d = 200;
    public static void main(String[] args) {
        new IntegerTest().test();
    }
    public void test(){
        System.out.println(a==b);
        System.out.println(c==d);
    }
}
           

輸出結果如下:

true  // 表明 a 和 b 是同一個對象
false // 表明 c 和 d 不是同一個對象
           

大家可能已經知道這是關于

Java

整數對象緩存(-128–127)的問題。

我們看下到底為什麼會這樣

反彙編

class

檔案

通過

javap -c

指令将

class

檔案進行反彙編,内容如下:

public class hua.lee.test.IntegerTest {
  // 此處是編譯後生成的對象初始化方法
  public hua.lee.test.IntegerTest();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: aload_0
       5: bipush        100
       7: invokestatic  #2                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
      10: putfield      #3                  // Field a:Ljava/lang/Integer;
      13: aload_0
      14: bipush        100
      16: invokestatic  #2                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
      19: putfield      #4                  // Field b:Ljava/lang/Integer;
      22: aload_0
      23: sipush        200
      26: invokestatic  #2                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
      29: putfield      #5                  // Field c:Ljava/lang/Integer;
      32: aload_0
      33: sipush        200
      36: invokestatic  #2                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
      39: putfield      #6                  // Field d:Ljava/lang/Integer;
      42: return

    ... // 省略部分
}
           

以變量

a

為例,它的核心指派部分是:

4: aload_0
       5: bipush        100
       7: invokestatic  #2                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
      10: putfield      #3                  // Field a:Ljava/lang/Integer;
           

invokestatic

是執行一個靜态方法的指令,這裡執行的是

Integer.valueOf()

,也就是說

Java

的自動裝箱其實就是編譯器編譯時将

Integer a = 100;

轉換為

Integer a = Integer.valueOf(100);

的操作

Integer.valueOf()

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);
    }
           

可以看到

  • 當傳入的數值在

    IntegerCache.low

    IntegerCache.high

    之間的話,會傳回

    IntegerCache.cache

    數組中的

    Integer

    對象
  • 否則,

    new Integer()

IntegerCache

Integer

的内部類,代碼如下:

private static class IntegerCache {
        // low 是寫死的
        static final int low = -128;
        // 關于high,看樣子是可以動态調整
        static final int high;
        // 用來緩存 Integer 對象的集合
        static final Integer cache[];
        static {
            // high value may be configured by property
            int h = 127;
            // 從 java.lang.Integer.IntegerCache.high 屬性中讀取緩存的上限
            String integerCacheHighPropValue = sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
            // 屬性不為空,進行數值轉換處理
            if (integerCacheHighPropValue != null) {
                try {
                    int i = parseInt(integerCacheHighPropValue);
                    // 不能小于 127
                    i = Math.max(i, 127);
                    // 确定數組上限
                    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++);

            // assert 保證上限 >= 127 
            assert IntegerCache.high >= 127;
        }
        private IntegerCache() {}
    }
           

關于

Integer

的緩存問題我們就分析完了

  • Integer

    緩存的下限是固定的

    -128

  • Integer

    緩存的上限可以通過

    java.lang.Integer.IntegerCache.high

    設定,但是必須

    >=127

  • Integer

    在類初始化的時候就把緩存集合

    cahce

    建立好了,并且在類初始化時會将

    cahce

    集合填充完成