從 Java SE5 開始就提供了自動裝箱的特性,簡單一點說:
裝箱就是 自動將基本數據類型轉換爲包裝器類型;
拆箱就是 自動將包裝器類型轉換爲基本數據類型。java
//自動裝箱
Integer i = 10;
//自動拆箱
int n = i;
複製代碼
下表是基本數據類型對應的包裝器類型:面試
基本數據類型 | 包裝器類型 |
---|---|
byte(1字節) | Byte |
short(2字節) | Short |
int(4字節) | Integer |
long(8字節) | Long |
float(4字節) | Float |
double(8字節) | Double |
char(2字節) | Character |
boolean(4字節) | Boolean |
以 Integer 類爲例,下面看一段代碼:數組
public class Test {
public static void main(String[] args) {
Integer i = 10;
int j = i;
}
}
複製代碼
先編譯:javac Test.java
再反編譯:javap -c Test.class
字節碼輸出以下: 緩存
在裝箱的時候自動調用 Integer 的 valueOf (int) 方法;
拆箱的時候自動調用 Integer 的 intValue 方法。
所以能夠用一句話總結裝箱和拆箱的實現過程:
裝箱過程是經過調用包裝器的 valueOf 方法實現;
而拆箱過程是經過調用包裝器的 xxxValue 方法(xxx 表明對應的基本數據類型)。
複製代碼
下面列舉一些常見的與裝箱 / 拆箱有關的面試題。bash
public class Main {
public static void main(String[] args) {
Integer i1 = 100;
Integer i2 = 100;
Integer i3 = 128;
Integer i4 = 128;
System.out.println(i1==i2); // true
System.out.println(i3==i4); // false
}
}
複製代碼
輸出結果代表 i1 和 i2 指向的是同一個對象,而 i3 和 i4 指向的是不一樣的對象。
源碼分析一下 Integer 的 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);
}
複製代碼
其中,IntegerCache 的源碼實現以下:ui
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() {}
}
複製代碼
從這 2 段代碼能夠看出:spa
在經過 valueOf 方法建立 Integer 對象的時候,若是數值在 [-128,127] 之間,便返回指向靜態緩存 IntegerCache.cache 的數組中已經存在的對象的引用;不然建立一個新的 Integer 對象。3d
上面的代碼中 i1 和 i2 的數值爲 100,所以會直接從 cache 中取已經存在的對象,因此 i1 和 i2 指向的是同一個對象,而 i3 和 i4 則是分別指向不一樣的對象。code
public class Main {
public static void main(String[] args) {
Double i1 = 100.0;
Double i2 = 100.0;
Double i3 = 200.0;
Double i4 = 200.0;
System.out.println(i1==i2); // false
System.out.println(i3==i4); // false
}
}
複製代碼
其中 Double 的 valueOf 源碼以下:
public static Double valueOf(double d) {
return new Double(d);
}
複製代碼
注意:
Integer、Short、Byte、Character、Long 這幾個類的 valueOf 方法的實現是相似的。
Double、Float 的 valueOf 方法的實現是相似的。
public class Main {
public static void main(String[] args) {
Boolean i1 = false;
Boolean i2 = false;
Boolean i3 = true;
Boolean i4 = true;
System.out.println(i1==i2); // true
System.out.println(i3==i4); // true
}
}
複製代碼
Boolean 類的源碼的 valueOf 實現:
public static Boolean valueOf(boolean b) {
return (b ? TRUE : FALSE);
}
複製代碼
public static final Boolean TRUE = new Boolean(true);
public static final Boolean FALSE = new Boolean(false);
複製代碼
從這2段代碼能夠看到:
public class Main {
public static void main(String[] args) {
Integer a = 1;
Integer b = 2;
Integer c = 3;
Integer d = 3;
Integer e = 321;
Integer f = 321;
Long g = 3L;
Long h = 2L;
System.out.println(c==d); // true
System.out.println(e==f); // false
System.out.println(c==(a+b)); // true 拆箱 比較值
System.out.println(c.equals(a+b)); // true 先拆箱再裝箱,比較對象裏面的value值
System.out.println(g==(a+b)); // true
System.out.println(g.equals(a+b)); // false 類型不一樣
System.out.println(g.equals(a+h)); // true 拆箱、向上轉型、裝箱、比較value值
}
}
複製代碼
注意:
主要有如下這兩點區別: 1) 第一種方式不會觸發自動裝箱的過程;而第二種方式會觸發; 2) 在執行效率和資源佔用上的區別。第二種方式的執行效率和資源佔用在通常性狀況下要優於第一種狀況(注意這並非絕對的)。