如何理解Java中的自動拆箱和自動裝箱?


小偉剛畢業時面的第一家公司就被面試官給問住了,記憶尤深啊...

如何理解Java中的自動拆箱和自動裝箱?

自動拆箱?自動裝箱?什么鬼,聽都沒聽過啊,這...這..知識盲區...

回到家后小偉趕緊查資料,我透,這不就是問基本類型跟封裝類型嗎,面試官整啥名詞呢...

別問結果,問就是沒過。

1、 什么是自動裝箱,自動拆箱

定義:基本數據類型和包裝類之間可以自動地相互轉換

理解:裝箱就是自動將基本數據類型轉換為封裝類型,拆箱就是自動將封裝類型轉換為基本數據類型。

我們知道,Java中提供了四大類基本數據類型,分別是:整數、浮點數、字符型和布爾型,其中:

  • 整數包含:byte、int、short、long
  • 浮點數包含:float、double
  • 字符類型:char
  • 布爾類型:boolean

基本數據類型相信大家一定很熟悉了吧,來來來,說說他們的取值范圍~

數據類型 取值范圍
byte -128 ~ 127
short -32786 ~ 32767
int -4294967296 ~ 4294967295
long -2^64^ ~ 2^64^ -1
float 3.4e-038 ~ 3.4e+038
double 1.7e-308 ~ 1.7e+308
char \u0000 ~ \uffff
boolean true 、false

日常開發中,靠這些基本數據類型幾乎能夠滿足我們的需求,但是基本類型終究不是對象,往重了說不滿足面向對象的開發思想,往輕了說就是使用不方便。怎么講?例如做一些數據類型轉換,獲取int數據類型的取值范圍等等。

我們知道,類的優點在於它可以定義成員變量、成員方法,提供豐富便利的功能,因此Java在JDK1.0的時候就設計了基本數據類型的包裝類,而在JDK1.5中引入了新特性:自動裝箱和拆箱。

我們來看一下基本類型跟封裝類型之間的對應關系:

數據類型 封裝類
byte Byte
short Short
int Integer
long Long
float Float
double Double
char Character
boolean Boolean

2、 使用包裝類型后的便捷

我們以上邊提到的數據類型轉換為例,看看使用包裝類型后的便捷性。

小偉在數據庫中存放商品庫存用的是 varchar 類型來存儲的,所以在代碼中的實體與之對應的是 String,那么問題來了,既然是庫存,那么勢必就要用到加減乘除之類的運算,所以就需要先轉換成 數值類型(int\long\float等)來運算,我們看一下通過包裝類是如何快速轉換的「int\long\float」:

public class Test {
    public static void main(String[] args) {
        // 數據庫中的商品數量 number
        String number = "666";
        // 借助封裝了 Integer 轉換為 int
        int intVal = Integer.valueOf(number);
        // 借助封裝了 Float 轉換為 float
        float floatVal = Float.valueOf(number);
        // 借助封裝了 Long 轉換為 long
        long longVal = Long.valueOf(number);
        // 依次輸出三個值的內容
        System.out.println("int="+intVal);
        System.out.println("floatVal="+floatVal);
        System.out.println("longVal="+longVal);
    }
}

3、 落實自動裝箱、拆箱

看完了包裝類型的便捷性后,我們再來落實到自動裝箱、自動拆箱上...

怎么就自動裝箱,自動拆箱了呢?

上一段代碼,看看哪是自動裝箱跟自動拆箱:

// 自動裝箱
1. Integer a = 100;
// 自動拆箱
2. int b = a;

自動裝箱,相當於Java編譯器替我們執行了 Integer.valueOf(XXX);

自動拆箱,相當於Java編譯器替我們執行了Integer.intValue(XXX);

我們證實一下,首先通過 javac 編譯得到 class 文件,接着反編譯看看:

指令為:javap -c class文件名,得到下圖所示:

看完編譯器替我們做的,接下來我們再通過源碼看看,首先是自動裝箱 valueOf() 方法:

public static Integer valueOf(int i) {
 if (i >= IntegerCache.low && i <= IntegerCache.high)
  return IntegerCache.cache[i + (-IntegerCache.low)];
 return new Integer(i);
}

我們可以看到,首先是if方法, 對傳入的int 數值進行判斷,如果 i >= -128i <= 127 那么就會從IntegerCache緩存中獲取指定數字的封裝類,如果不存在則 new 出一個新的封裝類,關於 IntegerCache ,其內部實現了一個Integer的靜態常量數組,在類加載的時候,執行static靜態塊進行初始化-128~127之間的Integer對象,存放到cache數組中,cache屬於常量,存放在java的方法區中,對方法區不太了解的小伙伴可以先留空,后面我會單獨水一篇的~

額外補充一下:上邊我們只看了Integer封裝類的自動裝箱方法,從方法中我們了解了在-128~127之間使用了緩存,那么是不是意味着別的封裝類也是這樣呢?其實不是的,首先Integer使用緩存原因是該區間會被經常使用到,且數量個數比較確定,就256個值,所以為了提高效率,防止每次自動裝箱都創建一次對象實例,然后就你懂得~,而double、float浮點型是沒有使用緩存的,因為小數點的原因,所以在這個區間范圍內個數是比較泛的,即不適合緩存,沒有意義。

我們通過一段代碼看看這個緩存的效果吧:

public class Test2 {
    public static void main(String[] args) {
        Integer a = 100;
        Integer b = 100;
        Integer c = 200;
        Integer d = 200;
        System.out.println(a==b); // 打印true
        System.out.println(a==b); // 打印false
    }
}

接着再來看自動拆箱 intValue() 方法:

private final int value;

public int intValue() {
 return value;
}

這個方法就比較簡單了,調用時直接返回了基本數據類型的 value 值。

至此我們看完了自動裝箱、自動拆箱,以Integer為例我們知道了使用 valueOf() 方法實現裝箱,使用 intValue() 方法實現拆箱,接下來我們再結合幾行代碼重新回顧一下:

1. Integer a = new Integer(100);
2. Integer b = 100;
3. b+=100;
  • 第一行代碼:new 了一個 Integer 對象實例,將 int 類型的數據傳入包裝成了 Integer 類型。

  • 第二行代碼:首先我們知道 100 是 int 類型的,但是等待復制的 b 是 Integer 類型,此時就用到了自動裝箱,b = Integer.valueOf(100),將100包裝成包裝類了「通過反編譯驗證」

  • 第三行代碼:用到了自動裝箱+自動拆箱,b = b + 100 = Integer.intValye(b) + 100 此時計算結果得到的應該是 int 類型的 b,但是 b 又被限定了是 Integer 類型,所以就又要用到 Integet.valueOf() 自動裝箱。

4、 上才藝

才藝一:如何理解Java中的自動拆箱和自動裝箱?

答:自動裝箱就是將基本數據類型自動轉換為封裝類型,自動拆箱是將封裝類型自動轉換為基本數據類型。

才藝二:能說一下是通過哪些方法實現自動拆箱、裝箱的嗎?

答:以Integer為例,使用Integer.valueOf()方法實現裝箱,使用Integer.intValue()方法實現拆箱。

推薦閱讀:

跟小偉一起學習類加載機制

為什么有這么多領優惠劵的群?

單招計算機類哪個專業比較好


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM