Java基本類型的裝箱

JDK:1.8

/**
 * 用於測試基本數據類型的自動拆箱和自動裝箱
 */
public class AutoBox {

    /**
     * 測試整型的自動拆箱和緩衝
     */
    static class TestInt{

        public static void main(String[] args){

            Integer integer = new Integer(100);
            Integer integer1 = 100;
            Integer integer2 = 100;

            System.out.println(integer == integer1);//false
            System.out.println(integer1 == integer2);//true
            System.out.println(integer == integer2);//false
        }

        /*
        這個是上面主函數的字節碼,現在來分析爲什麼輸出是如此:
        public static void main(java.lang.String[]);
            Code:
               0: new           #2                  // class java/lang/Integer
               3: dup
               4: bipush        100
               6: invokespecial #3                  // Method java/lang/Integer."<init>":(I)V
               //使用new在堆裏面實例化一個integer對象
               9: astore_1
              10: bipush        100
              12: invokestatic  #4                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
              //以100爲參數調用integer類的靜態方法
              15: astore_2
              16: bipush        100
              18: invokestatic  #4                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
              //以100爲參數調用integer類的靜態方法
              21: astore_3
              22: getstatic     #5                  // Field java/lang/System.out:Ljava/io/PrintStream;
              25: aload_1
              26: aload_2
              27: if_acmpne     34
              30: iconst_1
              31: goto          35
              34: iconst_0
              35: invokevirtual #6                  // Method java/io/PrintStream.println:(Z)V
              38: getstatic     #5                  // Field java/lang/System.out:Ljava/io/PrintStream;
              41: aload_2
              42: aload_3
              43: if_acmpne     50
              46: iconst_1
              47: goto          51
              50: iconst_0
              51: invokevirtual #6                  // Method java/io/PrintStream.println:(Z)V
              54: getstatic     #5                  // Field java/lang/System.out:Ljava/io/PrintStream;
              57: aload_1
              58: aload_3
              59: if_acmpne     66
              62: iconst_1
              63: goto          67
              66: iconst_0
              67: invokevirtual #6                  // Method java/io/PrintStream.println:(Z)V
              70: return
         在我們使用自動裝箱來進行實例化integer對象時,第12、18行都是調用的integer類的靜態方法valueOf,也就是說,導致
         integer1與integer2指向同一個對象,而與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);
         }
         從上面的源碼看出來在傳入的值處於某個區間時,返回的是同一個對象,只有在超出這個範圍時纔是在堆裏面創建一個新的對象
         也就是說integer1與integer2地址相同是因爲100處於這個區間裏面,現在繼續分析IntegerCache的源碼一探究竟,源碼如下:

         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:告訴我們這個可以配置?在類文檔裏面找到可以使用-XX:AutoBoxCacheMax=<size>配置
                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);//high - low + 1 = Integer.MAX_VALUE;->high = Integer.MAX_VALUE - (-low) -1
                    } catch( NumberFormatException nfe) {}
                }
                high = h;
                //這個就是被緩存的整型對象數組
                cache = new Integer[(high - low) + 1];
                int j = low;
                //在這裏進行了實例化,所以只要是配置範圍裏面的對象都已經被事先創建出來了。
                for(int k = 0; k < cache.length; k++)
                    cache[k] = new Integer(j++);
            }
        }
        綜合上面的分析,如果我們使用自動裝箱的方式,相當於隱式調用了valueOf函數,而這個函數會先判斷該數值是否已經在配置
        的緩存裏面,如果在就直接返回,如果不在才創建新的對象,所以這就是上面輸出的解釋了。
        剩下的基本數據類型包裝的緩存如下:
        Boolean:沒有,一個正負要撒子緩存嘛。
        Byte:緩存-128-127,恐怖,全部被緩存了,每一個Byte都被緩存了。
        private static class ByteCache {
            private ByteCache(){}
            static final Byte cache[] = new Byte[-(-128) + 127 + 1];
            static {
                for(int i = 0; i < cache.length; i++)
                    cache[i] = new Byte((byte)(i - 128));
            }
        }
        Character:緩存0-127
        private static class CharacterCache {
            private CharacterCache(){}
            static final Character cache[] = new Character[127 + 1];
            static {
                for (int i = 0; i < cache.length; i++)
                    cache[i] = new Character((char)i);
            }
        }
        Short: 緩存-128-127
        private static class ShortCache {
            private ShortCache(){}
            static final Short cache[] = new Short[-(-128) + 127 + 1];
            static {
                for(int i = 0; i < cache.length; i++)
                    cache[i] = new Short((short)(i - 128));
            }
        }
        Float:沒有!
        Double:沒有!
        Long:緩存-128-127
        private static class LongCache {
            private LongCache(){}
            static final Long cache[] = new Long[-(-128) + 127 + 1];
            static {
                for(int i = 0; i < cache.length; i++)
                    cache[i] = new Long(i - 128);
            }
        }
        總結:只有int的範圍可以配置,以後再有人問你int類型自動拆箱和裝箱的過程,先問他-XX:AutoBoxCacheMax=<size>參數配置
        的是啥,哈哈哈哈。(size大於127纔有效,否則都是默認的127)
         */
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章