java Integer包裝類裝箱的一個細節


java有八個基本數據類型,每個都有對應的一個包裝類,比如int對應的Integer。從jdk1.5開始,java引入了自動拆裝箱,可以直接進行形如Integer i = 20形式的賦值,編譯器會自動將其轉換為Integer i = Integer.valueOf(20)進行裝箱,拆箱則是將int j = i的形式轉換成了int j = i.intValue()。

裝箱有個細節,如果不注意很容易出錯,來看一下:

Integer i = 20;
Integer j = Integer.valueOf(20);

System.out.println(i == j);

上面的代碼輸出為

true

好像沒什么問題,那我們形式不變,將數字20換成200,即

i = 200;
j = Integer.valueOf(200);
System.out.println(i
== j);

同樣的判斷,輸出變成了:

false

這是為什么呢?


先明確一點,經過編譯器編譯后,Integer i = 20轉換成了Integer i = Integer.valueOf(20),和Integer j = Integer.valueOf(20)的定義完全一樣,那為什么將20換成了200后判斷結果不一樣了呢?
我們來看看Integer.valueOf(int i)方法的內部:

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


可以看出當i在某個區間內時,直接返回了緩存數組IntegerCache.cache中的一個值,超出區間才new一個新的Integer對象。到這里我們大概就可以得出結論:20在緩存范圍內所以直接用了緩存,但是200超出了緩存區間所以new了新對象,和原來對象的地址當然不會相同,所以返回false
再來看看IntegerCache,這是一個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) {
                int i = parseInt(integerCacheHighPropValue);
                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() {}
    }

 

可以看出默認的緩存區間是-128~127,那么什么情況下會修改這個范圍呢,修改了某個虛擬機參數的時候,通過代碼也可看出,設置的這個緩存上限java.lang.Integer.IntegerCache.high值不能小於127,小於的話就會被賦予127,從而失效。
那么這個值怎么設置呢?我們來看看jdk源碼中怎么解釋IntegerCache這個靜態內部類:

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. The size of the cache may be controlled by the -XX:AutoBoxCacheMax= option. During VM initialization, java.lang.Integer.IntegerCache.high property may be set and saved in the private system properties in the sun.misc.VM class.


大概意思是:

將-128到127(包含)的數字做緩存以供自動裝箱使用。緩存在第一次使用時被初始化。大小可以由JVM參數-xx:autoboxcachemax=option來指定。JVM初始化時此值被設置成java.lang.Integer.IntegerCache.high屬性並作為私有的系統屬性保存在sun.misc.vm.class中。

可以得到結論:這個緩存的high值是由JVM參數 -XX:AutoBoxCacheMax= option來指定的。

上述jdk源碼來源於jdk1.7,不同版本實現略有不同,但思路一致。

 

這種共享常用對象的思路有一個名字,叫享元模式,英文名叫Flyweight,即共享的輕量級元素。其他包裝類如Boolean、Byte、Short、Long、Charactor都有類似的實現。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM