java自動裝箱拆箱總結
阿新 • • 發佈:2019-02-01
對於java1.5引入的自動裝箱拆箱,之前只是知道一點點,最近在看一篇部落格時發現自己對自動裝箱拆箱這個特性瞭解的太少了,所以今天研究了下這個特性。以下是結合測試程式碼進行的總結。
測試程式碼:
int a = 1;
Integer b = 1;
Integer c = 1;
Integer d = 2;
Integer e = 3;
Integer f = 128;
Integer g = 128;
Long h = 3L;
Double m = 4.0 ;
Double n = 4.0;
Float p = 5f;
Float q = 5f;
System.out.println("a == b : " + (a == b)); //true
System.out.println("b ==c : " + (b == c)); //true
System.out.println("e == (c + d) : " + (e == (c + d))); //true
System.out.println("e.equals(c + d) : " + (e.equals(c + d))); //true
System.out.println("h == (c + d) : " + (h == (c + d))); //true
System.out.println("h.equals(c + d) : " + (h.equals(c + d))); //false
System.out.println("f == g : " + (f == g)); //false
System.out.println("m == n : " + (m == n)); //false
System.out .println("p == q : " + (p == q)); //false
System.out.println("m == d * 2 : " + (m == d * 2)); //true
System.out.println("p == (d + e) : " + (p == (d + e))); //true
測試輸出結果與說明:
1. a == b : true
當基本型別包裝類與基本型別值進行==運算時,包裝類會自動拆箱。即比較的是基本型別值。
具體實現上,是呼叫了Integer.intValue()方法實現拆箱。
可以在測試程式碼處打斷點,使用F5快捷鍵step
into至每一步執行方法,會看到呼叫了Integer.intValue()方法實現了拆箱。
2. b == c : true
b和c型別均為Integer包裝類,故對基本型別進行自動裝箱後賦值給b和c。
在進行==運算時不會觸發拆箱操作。所以比較的是引用地址,說明b和c是同一個物件。
java中自動裝箱呼叫的是Integer.valueOf()方法實現的,可以像例1一樣打斷點驗證。
為什麼b和c 會是同一個物件呢?檢視Integer.valueOf()方法實現即可知道,如下:
下面的程式碼中可以看到,對於-128至127這256個值,直接獲取的IntegerCache中的值。
而IntegerCache是Integer中的一個靜態內部類,
裡面將-128至127(即一個位元組所能表示的所有帶符號值 -2^7至2^7-1)的包裝類存在了一個數組中。
對於-128到127之間的數,直接從陣列中獲取,其他的數則使用new生成。所以此處輸出true。
public static Integer valueOf(int i) {
if(i >= -128 && i <= IntegerCache.high)
return IntegerCache.cache[i + 128];
else
return new Integer(i);
}
private static class IntegerCache {
static final int high;
static final Integer cache[];
static {
final int low = -128;
// high value may be configured by property
int h = 127;
if (integerCacheHighPropValue != null) {
// Use Long.decode here to avoid invoking methods that
// require Integer's autoboxing cache to be initialized
int i = Long.decode(integerCacheHighPropValue).intValue();
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++);
}
3. e == (c + d) : true
包裝類在執行加減乘除求餘等運算時,會觸發拆箱操作,故c、d拆箱後相加,
結果為基本型別;然後e與基本型別進行==運算,觸發拆箱操作。
4. e.equals(c + d) : true
首先,c + d 拆箱運算得到基本型別值;然後當進行equals運算時,
會觸發基本型別值的裝箱操作,c + d 的結果會自動裝箱為包裝類;最後與e進行equals運算。
5. h == (c + d) : true
運算順序與上面例3中一致,唯一區別是h自動拆箱是呼叫了Long.longValue()實現。
6. h.equals(c + d) : false
運算順序與上面例4中一致,為false的原因在於c + d的運算結果自動裝箱後型別為Integer,
而h的型別為Long,型別不一樣,equals的結果為false。
7. f == g : false
請參考上面例2中的解釋。
超出了-128至127的快取範圍,故在valueOf()方法中使用new生成了新物件。
8. m == n : false
p == q : false
與上面例子1、2中的結果不同,對於Boolean、Byte、Character、Short、Integer、Long六種基本型別,
對於一個位元組以內的值-128到127(Boolean只有true和false)都實現了快取機制。
不在此範圍的數才在對應的valueOf()方法中new出一個新的物件。
但是對於Double和Float型別的浮點資料,在-128到127之間除了256個整數外還有無數的小數,
故java中沒有實現Double和Float中一些數的快取。
所以,對於Double和Float的自動裝箱,都是new出新的物件。故此兩例均輸出false。
10. m == d * 2 : true
p == (d + e) : true
請參考例3和例5。
反編譯後代碼:
使用java反編譯工具,對class位元組碼檔案進行反編譯,結果如下所示。從下面的反編譯程式碼,我們可以看到java是如何實現自動裝箱、拆箱的。
int a = 1;
Integer b = Integer.valueOf(1);
Integer c = Integer.valueOf(1);
Integer d = Integer.valueOf(2);
Integer e = Integer.valueOf(3);
Integer f = Integer.valueOf(128);
Integer g = Integer.valueOf(128);
Long h = Long.valueOf(3L);
Double m = Double.valueOf(4.0D);
Double n = Double.valueOf(4.0D);
Float p = Float.valueOf(5.0F);
Float q = Float.valueOf(5.0F);
System.out.println("a == b : " + (a == b.intValue()));
System.out.println("b ==c : " + (b == c));
System.out.println("e == (c + d) : " + (e.intValue() == c.intValue() + d.intValue()));
System.out.println("e.equals(c + d) : " + e.equals(Integer.valueOf(c.intValue() + d.intValue())));
System.out.println("h == (c + d) : " + (h.longValue() == c.intValue() + d.intValue()));
System.out.println("h.equals(c + d) : " + h.equals(Integer.valueOf(c.intValue() + d.intValue())));
System.out.println("f == g : " + (f == g));
System.out.println("m == n : " + (m == n));
System.out.println("p == q : " + (p == q));
System.out.println("m == d * 2 : " + (m.doubleValue() == d.intValue() * 2));
System.out.println("p == (d + e) : " + (p.floatValue() == d.intValue() + e.intValue()));