Java基礎之包裝類的自動裝箱和拆箱詳解

Java基礎之包裝類的自動裝箱和拆箱詳解

定義

在java中,資料型別可以分為兩大類,即基本資料型別和引用資料型別,基本資料型別的資料不是物件,所以對於要將資料型別作為物件來使用的情況,java提供了相對應的包裝類。(關於包裝類的詳細介紹請參看部落格Java基礎之常用類詳解

本篇部落格主要講述包裝類的自動裝箱和拆行機制。

所謂裝箱,就是把基本資料型別用它們相對應的引用型別包起來,使它們可以具有物件的特質,如我們可以把int型別包裝成Integer型別的物件,或者把double包裝秤Double,等等。

所謂拆箱,就是和裝箱的方向相反,將Integer即Double這樣的引用型別的物件重新簡化成基本資料型別的資料。

而java JDK引入的自動裝箱和拆箱就是編譯器來依據我們編寫的程式碼,決定是否進行裝箱和拆箱動作。即無需使用valueOf()和intValue()等方法。(如果這方面不熟悉請參看部落格Java基礎之常用類詳解

關於自動裝箱拆箱機制的注意事項

這是本篇部落格要講述的重點

先看一個小例子:


public class WrapperText {
public static void main(String[] args) {
Integer a = 100;
Integer b = 100;
Integer c = 200;
Integer d = 200;
System.out.println(a == b);//1
System.out.println(a == 100);//2
System.out.println(c == d);//3
System.out.println(c == 200);//4
}
}

如果我們對於Java中自動裝箱和拆箱操作了解不夠深入的話,一定會這麼想:自動裝箱後,abcd都是Integer物件的不同引用,“==”操作符又是用來比較物件引用的,所以1和3都應輸出false。而對於2和4,由於a和c都進行了自動拆箱,因此其比較是基本資料型別的比較。“==”操作符比較的使它們的值,所以2和4因該輸出true。即最終結果輸出:
false
true
false
true
但是正確的結果卻是:
這裡寫圖片描述
我們看到1的結果為true,3的結果為false,這是為什麼呢。其實很簡單,自動裝箱過程其實是呼叫了valueOf()的方法,而valueOf()方法的原始碼為:

public static Integer valueOf(int i) {
assert IntegerCache.high >= 127;
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i   (-IntegerCache.low)];
return new Integer(i);
}
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
int h = 127;
String integerCacheHighPropValue =
sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
if (integerCacheHighPropValue != null) {
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 = h;
cache = new Integer[(high - low)   1];
int j = low;
for(int k = 0; k < cache.length; k  )
cache[k] = new Integer(j  );
}
private IntegerCache() {}
}

通過閱讀原始碼,可以發現,java內部為了節省記憶體,IntegerCache類中有一個陣列快取了值從-128到127的Integer物件。當我們呼叫Integer.valueOf(int i)的時候,如果i的值時結餘-128到127之間的,會直接從這個快取中返回一個物件,否則就new一個新的Integer物件。因此,1為true,3為false。

最後分享一道與之相關的很有意思的題目:

請提供一個對i的宣告,將下面的迴圈轉變成為一個無限迴圈:

while(j <= i && i <= j && i != j){
}

相信如果仔細閱讀了本篇部落格,這道題一定能夠很輕鬆的解決。