對于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()));
~~~
參考文章:
[ ①Java 自動裝箱和拆箱](http://blog.csdn.net/jackiehff/article/details/8509056)
[②Java自動裝箱與拆箱及其陷阱](http://blog.csdn.net/jairuschan/article/details/7513045)
[③深入剖析Java中的裝箱和拆箱](http://www.cnblogs.com/dolphin0520/p/3780005.html)
[④四道Java基礎題 你能對幾道?](http://blog.csdn.net/soul_code/article/details/50369947)