1. 程式人生 > >【JAVA】談談拆箱與裝箱

【JAVA】談談拆箱與裝箱

                                          談談裝箱與拆箱

一、何為包裝型別

Java是一種面向物件的語言,但是它不是純面向物件的。Java中存在基本資料型別,談不上物件。為了向純面向物件靠攏,Java5的時候推出了基本資料型別的包裝型別。

基本資料型別與包裝型別的對應關係如下: 



二、何為裝箱與拆箱

裝箱就是將基本資料型別轉化為包裝型別,那麼拆箱就是將包裝型別轉化為基本資料型別。

以基本資料型別int為例:

package day1119;

public class TestBox {
    public static void main(String[] args) {
        //自動裝箱,底層其實執行了Integer a=Integer.valueOf(1);
        Integer a = 1;
        //自動拆箱,底層其實執行了int b=a.intValue();
        int b = a;
    }
}

Integer的valueOf(int i)方法可以將一個基本資料型別轉化為對應的包裝型別,即裝箱方法。

而Integer的intValue()方法則可以將一個包裝型別轉化為對應的基本資料型別,即拆箱方法。


三、裝箱與自動裝箱的區別

裝箱:利用Integer的構造方法Integer(int value),即Integer c=new Integer(1);

自動裝箱:或者叫隱式裝箱,直接給Integer賦值,即Integer d=1,在編譯的時候,會呼叫Integer.valueOf()方法完成裝箱。

相比而言,自動裝箱可能比裝箱具有更高的效率,體現在自動裝箱的快取上,下面從幾道題目來講自動裝箱的快取。


四、相關面試題目

第一題:以下程式碼的輸出結果為?(==號兩邊如果都是引用型別的話,則判斷它們是否指向同一個物件。如果都是基本資料型別的話,則判斷它們的數值是否相等)

package day1119;

public class TestBox2 {
    public static void main(String[] args) {
        Integer a = 100;
        Integer b = 100;
        Integer c = 200;
        Integer d = 200;
        System.out.println(a == b);
        System.out.println(c == d);
    }
}

也許有些人認為他們是四個各不相同的物件,兩個式子都返回false。

實際執行後發現輸出:

為什麼一個是true,一個是false呢?

剛才我們知道,Integer a=100這條語句會觸發自動裝箱,而自動裝箱的方法為Integer.valueOf()方法,讓我們去尋找這個方法,一探究竟。

觀察Integer類的原始碼中的valueOf()

    /**
     * Returns an {@code Integer} instance representing the specified
     * {@code int} value.  If a new {@code Integer} instance is not
     * required, this method should generally be used in preference to
     * the constructor {@link #Integer(int)}, as this method is likely
     * to yield significantly better space and time performance by
     * caching frequently requested values.
     *
     * This method will always cache values in the range -128 to 127,
     * inclusive, and may cache other values outside of this range.
     *
     * @param  i an {@code int} value.
     * @return an {@code Integer} instance representing {@code i}.
     * @since  1.5
     */
    public static Integer valueOf(int i) {
        if (i >= IntegerCache.low && i <= IntegerCache.high)
            return IntegerCache.cache[i + (-IntegerCache.low)];
        return new Integer(i);
    }

可以看得出,當i的值位於[-128,127]的時候,會直接返回Integer快取陣列中相應物件的引用,如果i大於127或小於-128,會重新建立一個Integer例項,並返回。

那麼第一條式子a和b的值都在快取範圍內,因此他們指向同一個物件,因此返回true。c和d的值不在範圍內,都是通過new創建出來的,因此不是同一個物件,返回false。

注意:Byte、Short、Integer、Long、Character的valueOf()實現機制類似。

其中相同值的Byte比較永遠返回true,因為byte取值範圍就是[-128,127]。

Short、Integer、Long的valueOf()基本一樣,i的範圍都需要在[-128,127]。

Character中i的範圍只要小於等於127即可,因為char最小值為0,本來就大於等於-128。

但是Float、Double中的valueOf(),永遠返回新建立的物件,因為一個範圍內的整數是有限的,但是小數卻是無限的,無法儲存在快取中。

Boolean中只有兩個物件,要麼是true的Boolean,要麼是false的Boolean,只要boolean的值相同,Boolean就相等。


第二題:以下程式碼的輸出結果為?

package day1119;

public class TestBox3 {
    public static void main(String[] args) {
        Integer a = 1;
        Integer b = 2;
        Integer c = 3;
        Long d = 2L;
        Long e = 3L;
        int f = 2;

        //一旦有包裝型別和數值型別判斷==時,則觸發包裝型別的自動拆箱,轉為數值型別的比較
        System.out.println(new Integer(300) == 300);//返回true

        //一旦有包裝型別和數值型別發生運算時,則觸發包裝型別的自動拆箱,轉為數值型別的運算
        System.out.println(c == (a + f));//返回true

        //一旦有包裝型別和包裝型別發生運算時,則觸發包裝型別的自動拆箱,轉為數值型別的運算
        System.out.println(c == (a + b));//返回true

        //只有物件型別才有equals方法,因此首先a,b觸發包裝型別的自動拆箱,轉為數值型別的運算。
        //運算完,再將結果3自動裝箱,Integer重寫了equals,因此可以轉為包裝型別與包裝型別的比較。
        //當兩邊的包裝型別不一致時,必定返回false。
        //當兩邊的包裝型別一致時,再進行拆箱,判斷兩者代表的數值是否相等。
        System.out.println(c.equals(a + b));//返回true

        //不同資料型別的數值進行運算,首先會將低精度的資料型別轉化為高精度的資料型別,即自動型別轉換。
        //比如現在的int+long,會提升到long+long,再進行運算。
        System.out.println(e == (a + d));//返回true

        //==號兩邊型別不一致時,直接執行自動拆箱,比較之後的數值
        System.out.println(e == (a + b));//返回true

        //依次經歷自動拆箱,自動型別轉換、運算、自動裝箱,型別比較,拆箱,數值比較
        System.out.println(e.equals(a + d));//返回true

        //依次經歷自動拆箱,自動型別轉換、運算、自動裝箱,型別比較,兩邊型別不一致,直接返回false
        System.out.println(c.equals(a + d));//返回false


    }
}

五、總結

如果想要深入瞭解自動裝箱拆箱的過程,必須得反編譯class檔案,瞭解底層編譯的細節,才可以解除自己此方面的疑問。