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)
*/
}
}