天天看點

java的自動裝箱_詳解Java 自動裝箱與拆箱的實作原理

詳解Java 自動裝箱與拆箱的實作原理

釋出于 2020-7-4|

複制連結

本篇文章主要介紹了詳解Java 自動裝箱與拆箱的實作原理,小妖覺得挺不錯的,現在分享給大家,也給大家做個參考。一起跟随小妖過來看看吧

什麼是自動裝箱和拆箱自動裝箱就是Java自動将原始類型值轉換成對應的對象,比如将int的變量轉換成Integer對象,這個過程叫做裝箱,反之将Integer對象轉換成int類型值,這個過程叫做拆箱。因為這裡的裝箱和拆箱是自動進行的非人為轉換,是以就稱作為自動裝箱和拆箱。原始類型byte, short, char, int, long, float, double 和 boolean 對應的封裝類為Byte, Short, Character, Integer, Long, Float, Double, Boolean。下面例子是自動裝箱和拆箱帶來的疑惑

```java

public class Test {

public static void main(String[] args) {

test();

}

public static void test() {

int i = 40;

int i0 = 40;

Integer i1 = 40;

Integer i2 = 40;

Integer i3 = 0;

Integer i4 = new Integer(40);

Integer i5 = new Integer(40);

Integer i6 = new Integer(0);

Double d1=1.0;

Double d2=1.0;

System.out.println("i=i0\t" + (i == i0));

System.out.println("i1=i2\t" + (i1 == i2));

System.out.println("i1=i2+i3\t" + (i1 == i2 + i3));

System.out.println("i4=i5\t" + (i4 == i5));

System.out.println("i4=i5+i6\t" + (i4 == i5 + i6));

System.out.println("d1=d2\t" + (d1==d2));

System.out.println();

}

}

```

請看下面的輸出結果跟你預期的一樣嗎?輸出的結果:

i=i0    true

i1=i2   true

i1=i2+i3    true

i4=i5   false

i4=i5+i6    true

d1=d2 false

為什麼會這樣?帶着疑問繼續往下看。自動裝箱和拆箱的原理自動裝箱時編譯器調用valueOf将原始類型值轉換成對象,同時自動拆箱時,編譯器通過調用類似intValue(),doubleValue()這類的方法将對象轉換成原始類型值。明白自動裝箱和拆箱的原理後,我們帶着上面的疑問進行分析下Integer的自動裝箱的實作源碼。如下:

```java

public static Integer valueOf(int i) {

//判斷i是否在-128和127之間,如果不在此範圍,則從IntegerCache中擷取包裝類的執行個體。否則new一個新執行個體

if (i >= IntegerCache.low && i = 127;

}

private IntegerCache() {}

}

```

Integer i1 = 40; 自動裝箱,相當于調用了Integer.valueOf(40);方法。

首先判斷i值是否在-128和127之間,如果在-128和127之間則直接從IntegerCache.cache緩存中擷取指定數字的包裝類;不存在則new出一個新的包裝類。

IntegerCache内部實作了一個Integer的靜态常量數組,在類加載的時候,執行static靜态塊進行初始化-128到127之間的Integer對象,存放到cache數組中。cache屬于常量,存放在java的方法區中。

接着看下面是java8種基本類型的自動裝箱代碼實作。如下:

```java

//boolean原生類型自動裝箱成Boolean

public static Boolean valueOf(boolean b) {

return (b ? TRUE : FALSE);

}

//byte原生類型自動裝箱成Byte

public static Byte valueOf(byte b) {

final int offset = 128;

return ByteCache.cache[(int)b + offset];

}

//byte原生類型自動裝箱成Byte

public static Short valueOf(short s) {

final int offset = 128;

int sAsInt = s;

if (sAsInt >= -128 && sAsInt = IntegerCache.low && i = -128 && l 通過分析源碼發現,隻有double和float的自動裝箱代碼沒有使用緩存,每次都是new 新的對象,其它的6種基本類型都使用了緩存政策。

使用緩存政策是因為,緩存的這些對象都是經常使用到的(如字元、-128至127之間的數字),防止每次自動裝箱都建立一此對象的執行個體。

而double、float是浮點型的,沒有特别的熱的(經常使用到的)資料的,緩存效果沒有其它幾種類型使用效率高。下面在看下裝箱和拆箱問題解惑。

```java

//1、這個沒解釋的就是true

System.out.println("i=i0\t" + (i == i0)); //true

//2、int值隻要在-128和127之間的自動裝箱對象都從緩存中擷取的,是以為true

System.out.println("i1=i2\t" + (i1 == i2)); //true

//3、涉及到數字的計算,就必須先拆箱成int再做加法運算,是以不管他們的值是否在-128和127之間,隻要數字一樣就為true

System.out.println("i1=i2+i3\t" + (i1 == i2 + i3));//true

//比較的是對象記憶體位址,是以為false

System.out.println("i4=i5\t" + (i4 == i5)); //false

//5、同第3條解釋,拆箱做加法運算,對比的是數字,是以為true

System.out.println("i4=i5+i6\t" + (i4 == i5 + i6));//true

//double的裝箱操作沒有使用緩存,每次都是new Double,是以false

System.out.println("d1=d2\t" + (d1==d2));//false

```