Java中的自動拆裝箱

Java中的自動拆裝箱


    Java語言中,基本類型和它對應的封裝類型直接可以相互複製,共同參與運算。其實,經過編譯後並不是直接使用不同的類型來進行賦值和運算,而是採用了自動拆裝箱的方式把數據類型進行了變化。自動拆裝箱只是JDK語法糖技術中的一個。如下的代碼是可以通過編譯並且成功運行的:
    
    public void assignment(){
        int a = 1;
        Integer b = a;
        Integer c = 1;
        int d = c;
        int e = a + b;
        Integer f = c + d;    

        System.out.println(e);
        System.out.println(f);
    }

通過javap命令,的這個方法的虛擬機指令序列
 public void assignment();
    Code:
       0: iconst_1
       1: istore_1
       2: iload_1
       3: invokestatic  #2                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
       6: astore_2
       7: iconst_1
       8: invokestatic  #2                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
      11: astore_3
      12: aload_3
      13: invokevirtual #3                  // Method java/lang/Integer.intValue:()I
      16: istore        4
      18: iload_1
      19: aload_2
      20: invokevirtual #3                  // Method java/lang/Integer.intValue:()I
      23: iadd
      24: istore        5
      26: aload_3
      27: invokevirtual #3                  // Method java/lang/Integer.intValue:()I
      30: iload         4
      32: iadd
      33: invokestatic  #2                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
      36: astore        6
      38: getstatic     #4                  // Field java/lang/System.out:Ljava/io/PrintStream;
      41: iload         5
      43: invokevirtual #5                  // Method java/io/PrintStream.println:(I)V
      46: getstatic     #4                  // Field java/lang/System.out:Ljava/io/PrintStream;
      49: aload         6
      51: invokevirtual #6                  // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
      54: return

   從指令序列的第三行和第八行可以看出,把int類型的值賦給Integer類型的變量經過編譯後,變成了先利用裝箱方法Integer.varlueOf()把int類型包裝成Integer類型,然後再複製給Integer類型的變量。
   
    第13行的指令意味着,把Integer類型的值賦值給int類型變量需要利用拆箱方法Integer.intValue()先得到int類型的值,然後再賦值給int類型的變量。

   第18到24行代表代碼中的int e = a + b。Integer類型的變量和int類型的變量相加,Integer變量會先轉換成int類型,再進行相加運算。得到的結果是int類型。


    Java不通於c語言,不能重載加減乘除等運算符。所以在進行元素時,包裝類型都需要拆箱成基本類型才能運算。如果包裝類型爲null,則會報出空指針異常。

    但是,不論包裝類型還是基本類型都可以通過==操作符來比較兩個變量是否相等,包裝類型可以使用equeals方法比較兩個對象。那麼,包裝類型和基本類型在比較時都會進行哪些類型轉換呢?看下面的實驗

   public void compare(){
        Integer a = 129;
        Integer b = 129;
        int c = 129;
        Integer e = 127;
        Integer f = 127;

        System.out.println(a == b);
        System.out.println(a == c);
        System.out.println(a.equals(c));
        System.out.println(e == f);
    }

  要想知道都在哪些地方做了類型轉換,還是需要看看編譯後的指令,只不過指令代碼有點長不做粘貼了。最後的結論是,比較a和c時,把a拆箱成了int值。也就是==比較包裝類和基本類型時,把包裝類型拆箱成了基本類型。

通過上面的實驗可以得出下面的結論:
1,包裝類型和基礎類型相互賦值時,利用對應的拆箱或裝箱方法把右值轉化成左值的類型。
2,包裝類型和基礎類型在一起混合運算(包括==),則把封裝類型拆箱成基本類型
3,equals方法是包裝類型特有的方法(繼承自Object),基本類型不能利用這個方法比較。

  這裏還有一個有意思的地方,a和b是不相等的,而e和f是相等的。產生這個現象的原因是,Integer類型利用了緩存技術,在其內部緩存了從-128到127範圍內的數據,每當需要這個範圍內的對象的時候就會返回緩存池中的對象。那麼,如果直接new兩個緩存範圍內的Integer對象,通過==判斷它們會相等嗎?不要想的那麼複雜,都new了,怎麼會相等。==操作符比較的是對象在內存中的位置,除非是同一個對象,不然一定不相等。


發佈了51 篇原創文章 · 獲贊 11 · 訪問量 25萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章