理解JDK1.5的自動裝箱拆箱

JDK1.5的升級引入了裝箱和拆箱概念,簡單說就是爲了簡化書寫。

  JDK1.5以前,建立Integer對象是須要這麼寫的  Integer i = new Integer("3");java

  JDK1.5以後,有了自動裝箱,建立Integer對象時,咱們能夠這樣寫  Integer i = 5;編程

1 int num = 3;
2 num = num + 4;
3 //這樣寫在JDK1.5中是沒有問題的 4 Integer x = 3; 5 x = x + 4;

 

  這樣以來Integer就擁有了和 int 基本類型同樣的能力。表面看起來對象變的能夠直接進行運算,這對編程來講方便了不少。數組

裝箱:

  由 Integer x = new Integer(3);   簡化成:Integer i = 3; 能夠理解爲java自動幫咱們作了 x = new Integer(3)的操做。緩存

拆箱:

  x = x + 4; 對象是不能直接用來進行運算的,因此java會自動的作拆箱的操做,把(x+4)中的 x 自動拆箱(也就是調用Integer的intValue()方法,把x轉換爲int類型進行運算),當運算完成以後會把運算結果再次使用裝箱賦值給 x 。【整個表達式先拆箱運算完成以後再裝箱】ide

Integer的特殊之處

1 Integer a = new Integer(127);
2 Integer b = new Integer(127);
3 System.out.println(a==b);//false
4 System.out.println(a.equals(b));//true
5 
6 Integer c = 127;//JDK1.5之後,自動裝箱若是裝箱的是一個字節那麼該數據會被共享  不會從新開闢空間
7 Integer d = 127;
8 System.out.println(c==d);//true
9 System.out.println(c.equals(d));//true

  經過測試上面代碼的測試結果看出,JDK1.5之後Integer自動裝箱的數據若是是一個字節,那麼該數據會被共享,不會從新開闢新的空間。性能

  這就與咱們上面說的裝箱拆箱操做相矛盾了,若是Integer x = 3  真的代替了  Integer x = new Integer(3); 這裏已經使用了new,怎麼可能會不開闢新的空間呢?測試

  若是不開闢空間的話,那麼共享數據總要存在於一塊共享空間以內,難道會像字符串那樣維護了一個常量池?ui

 1     /**
 2      * Cache to support the object identity semantics of autoboxing for values between
 3      * -128 and 127 (inclusive) as required by JLS.
 4      *
 5      * The cache is initialized on first usage.  The size of the cache
 6      * may be controlled by the -XX:AutoBoxCacheMax=<size> option.
 7      * During VM initialization, java.lang.Integer.IntegerCache.high property
 8      * may be set and saved in the private system properties in the
 9      * sun.misc.VM class.
10      */
11 
12     private static class IntegerCache {
13         static final int low = -128;
14         static final int high;
15         static final Integer cache[];
16 
17         static {
18             // high value may be configured by property
19             int h = 127;
20             String integerCacheHighPropValue =
21                 sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
22             if (integerCacheHighPropValue != null) {
23                 int i = parseInt(integerCacheHighPropValue);
24                 i = Math.max(i, 127);
25                 // Maximum array size is Integer.MAX_VALUE
26                 h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
27             }
28             high = h;
29 
30             cache = new Integer[(high - low) + 1];
31             int j = low;
32             for(int k = 0; k < cache.length; k++)
33                 cache[k] = new Integer(j++);
34         }
35 
36         private IntegerCache() {}
37     }

  經過查找源碼發現,原來Integer類內部維護了一個靜態內部類,這是JDK1.5中,爲 Integer 的操做引入了一個新的特性,用來節省內存和提升性能。整型對象在內部實現中經過使用相同的對象引用實現了緩存和重用。this

  Javadoc 詳細的說明這個類是用來實現緩存支持,並支持 -128 到 127 之間的自動裝箱過程。最大值 127 能夠經過 JVM 的啓動參數 -XX:AutoBoxCacheMax=size 修改。 緩存經過一個 for 循環實現。從小到大的建立儘量多的整數並存儲在一個名爲 cache 的整數數組中。這個緩存會在 Integer 類第一次被使用的時候被初始化出來。之後,就可使用緩存中包含的實例對象,而不是建立一個新的實例(在自動裝箱的狀況下)。spa

  經過查看Integer的構造方法發現,沒有一個構造方法會從IntegerCache中取值,很顯然自動裝箱的操做並非經過new Integer()來完成的。應該是經過其餘的方法!

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

  經過查看源碼發現valueOf(int i)【只有這一個方法,其餘的重載方法未操做IntegerCache】中出現了對IntegerCache的操做。看源碼咱們瞭解到若是傳入的-128<i<127 就會從IntegerCache的cache數組中取出共享數據,若是不在這個範圍以內則使用new Integer(i)。

  由此也就完全明白了裝箱拆箱的內幕!

總結:

  > 裝箱使用的是valueOf(int i)

  > 拆箱使用的是intValue();

其實這種緩存行爲不只適用於Integer對象,針對全部整數類型的類都有相似的緩存機制。

有 ByteCache 用於緩存 Byte 對象

有 ShortCache 用於緩存 Short 對象

有 LongCache 用於緩存 Long 對象

有 CharacterCache 用於緩存 Character 對象

Byte、Short、Long有固定範圍:-128~127,對於 Character範圍是:0~127。

除了Integer能夠經過參數改變範圍外,其餘對象都不能夠。

相關文章
相關標籤/搜索