1. 程式人生 > >java自動裝箱拆箱特性

java自動裝箱拆箱特性

 http://www.cnblogs.com/dolphin0520/p/3780005.html

在Java SE5 之前,如果要生成一個數值為10的Integer物件,必須這樣進行:

Integer i = new Integer(10);

而在 從Java SE5開始  就提供了 自動裝箱 的特性,如果要生成一個數值為10的Integer物件,只需要這樣就可以了:

Integer i = 10;

這個過程中會自動根據數值建立對應的 Integer物件,這就是裝箱。

Integer i = 10;  //裝箱

int n = i;   //拆箱

簡單一點說:

裝箱就是  自動將基本資料型別轉換為包裝器型別;

拆箱就是  自動將包裝器型別轉換為基本資料型別。

 

在裝箱的時候自動呼叫的是 Integer的 valueOf( )  方法

在拆箱的時候自動呼叫的是 Integer的 intValue( )  方法

 

最關鍵的下面的面試問題:

public class Main {
    public static void main(String[] args) {
         
        Integer i1 = 100;
        Integer i2 = 100;
        Integer i3 = 200;
        Integer i4 = 200;
         
        System.out.println(i1==i2);
        System.out.println(i3==i4);
    }
}

控制檯結果:
true
false

為什麼是這個結果呢

看一哈 Integer 的 valueOf( ) 方法的具體實現:

public static Integer valueOf(int i) {
        
        if( i >= -128 && i <= IntegerCache.high )
            /* 如果傳入的 int 在 [-128,127] 之間,便返回
               指向IntegerCache.cache中已經存在的物件的引用 */
            return IntegerCache.cache[i + 128];
        else
            // 否則建立一個新的Integer物件
            return new Integer(i);
    }

我對這個 自動裝箱 過程的理解是 :

java 5 之後 ,java的開發者已經 默認準備了 [-128,127] 之間的128*2個 Integer 物件了,

這128*2個物件就像常量一樣被呼叫。

如果傳入的數字在此範圍內( 比如 i1、i2 ),則返回的都是人家提前備好的128*2個物件的引用

超出此範圍的話才會去建立新的物件並返回新物件的引用( 比如 i3、i4 ),

而每個新物件的引用又都是不一樣的,才導致了以上結果。

 

擴充套件:

Integer、Short、Byte、Character、Long這幾個類的valueOf方法的實現是類似的

Double、Float的valueOf方法的實現是類似的

Double類的 valueOf( ) 方法會採用與 Integer 類的 valueOf( ) 方法不同的實現

原因:在某個範圍內的整型數值的個數是有限的(128*2),而浮點數卻是無限的,沒有辦法提前準備

至於 Boolean包裝類 就更簡單了,總共只能有兩個值,直接就準備好兩個靜態final物件就好了:

public static final Boolean TRUE = new Boolean(true);

   
public static final Boolean FALSE = new Boolean(false);


public static Boolean valueOf(boolean b) {
        return (b ? TRUE : FALSE);
}

練習:

(1) '=='比較的是a和b的地址,即比較a和b指向的是否是同一個物件

(2) 對於 ' Integer==int ' 類似的比較,即兩個運算元中有一個是(int) 的情況, 比較的是數值是否相等(即Integer型別的那個物件會觸發自動拆箱的過程)

 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);
        System.out.println(e==f);
        System.out.println(c==(a+b));
        System.out.println(c.equals(a+b));
        System.out.println(g==(a+b));
        System.out.println(g.equals(a+b));
        System.out.println(g.equals(a+h));
    }

1)c == d  為 true 不用多講,自動裝箱時用的是一個物件

2)e == f   為false 也不多說 , 自動裝箱時超出了範圍[ -128,127 ],e和f都是新建立的物件,兩個物件的地址自然不一樣

3)a+b 時會觸發自動拆箱操作(為什麼? a和b兩個都是物件不拆箱怎麼進行相加運算?當然要轉化成基本資料型別才能+),加完以後變成了 c == (int) ,根據以上(2),c會自動拆箱,即最後比較的是數值

4)c.equals(a+b) 會先觸發自動拆箱過程(a+b),再觸發自動裝箱過程(為什麼?相加的結果是作為引數傳入c.equals()方法中的,equals()要的當然是Object,當然要裝一波箱),也就是說a+b,會先各自呼叫各自的 intValue() 方法,得到了加法運算後的數值之後,便呼叫 Integer.valueOf() 方法,再和c進行equals比較

5)同3):用到了(2):a+b之後為int型,Long要觸發自動拆箱

6)a+b 的結果自動裝箱的時候呼叫的是Integer.valueOf() 方法,但 g 是用的Long裡提前存好的[ -128,127 ]內的物件,而 a+b 用 是Integer裡提前存好[ -127,128 ]的物件,連型別都不一樣,當然是不同的兩個物件

7)a和h 自動拆箱後,運算時 a會自動型別轉換成範圍更大的 long ,自動裝箱時呼叫的是 Long.valueOf() 方法

 

執行結果:

true
false
true
true
true
false
true

如果對上面的具體執行過程有疑問,可以嘗試獲取反編譯的位元組碼內容進行檢視:

https://blog.csdn.net/swq463/article/details/84678142

這是程式碼加反編譯的結果:

public static void main(String[] args) {

    Integer b = 3; // Method java/lang/Integer.valueOf 自動裝箱

    Long c = 3L; // Method java/lang/Long.valueOf 自動裝箱

    System.out.println(c.equals(a)); // Method java/lang/Integer.valueOf a先自動裝箱
                                     // Method java/lang/Long.equals 
}