2014年5月4日 星期日

Java 包裹類別的 auto-boxing 與 auto-unboxing

在 Java 程式裡有一個類別庫 java.lang, 即使沒有用 import 指令匯入, JDK 在編譯時也會自動匯入, 因為此類別庫中有我們最常用的 wrapper 類別, String 類別, StringBuffer/StringBuilder 類別, Math 類別等等.

這裡要測試一下 wrapper 包裹類別的自動裝箱 (auto-boxing) 與自動拆箱 (auto-unboxing) 功能. 關於包裹類別參見 :

# Java 複習筆記 : 資料型態與語法

包裹類別的用途是將 8 種基本資料型態資料包裹成物件型態, 通常是利用其兩種建構子, 例如 :

Integer i=new Integer(100);  
Integer i=new Integer("100");

亦即建構子的傳入參數有兩種, 一是基本資料本身, 二是其字串型態, 8 種基本型態的包裹類別皆是如此, 參考 Java API :

# http://docs.oracle.com/javase/7/docs/api/

但是注意, 使用字串為建構子時, 其格式必須正確, 否則會產生格式例外 NumberFormat Exception, 例如下列範例雖然編譯成功, 但會有執行時期錯誤 :

public class wrapper1{
  public static void main(String[] args) {
    Integer i=new Integer("100.0");  //執行時發生格式錯誤例外
    System.out.println(i);
    }
  }

這是因為整數沒有小數點, 不能傳入 "100.0", 否則格式錯誤.

但下面範例則可以順利執行 :

public class wrapper1{
  public static void main(String[] args) {
    Double d=new Double("100");  //輸出 100.0
    System.out.println(d);
    }
  }

這是因為浮點數包括了整數, 本來就不一定會有小數點, 因此傳入整數格式是合法的.

在 JDK 1.5 版之後提供了包裹類別的 auto-boxing 與 auto-unboxing 功能, 亦即不需要利用建構子, JDK 會自動呼叫, 稱為 auto-boxing, 例如 :

public class wrapper1{
  public static void main(String[] args) {
    Integer i=100;
    System.out.println(i); //輸出 100
    Double d=100.0;
    System.out.println(d); //輸出 100.0
    }
  }

反過來看,  如果把包裹物件指定給基本型態變數, 在 JDK 1.5 版以前, 必須呼叫包裹物件的 xxxValue() 方法進行拆箱 (boxing) 才行.

public class wrapper1{
  public static void main(String[] args) {
    Integer i=100;
    System.out.println(i.intValue());  //輸出 100
    Double d=100.0;
    System.out.println(d.doubleValue());  //輸出 100.0
    }
  }

同樣地, 在 JDK 1.5 之後, 也不一定要用 xxxValue(), JDK 會自動呼叫 xxxValue() 進行拆箱 :


public class wrapper1{
  public static void main(String[] args) {
    Integer i=100;
    int ui=i;  //自動呼叫 intValue() 拆箱
    System.out.println(ui);  //輸出 100
    Double d=100.0;
    double ud=d;  //自動呼叫 doubleValue() 拆箱
    System.out.println(ud); //輸出 100.0
    }
  }

但要注意的是, 自動拆箱時的傳回值資料型態, 若指定給比傳回值還大的資料型態就 OK, 否則編譯時會出現 incompatible types 錯誤 :

public class wrapper1{
  public static void main(String[] args) {
    Integer i=100;
    //byte ui=i;  //自動拆箱型態不匹配 : 不可指定給較小的資料型態
    long ui=i; //自動拆箱型態匹配
    System.out.println(ui);
    double d=100.0;
    //float ud=f;  //自動拆箱型態不匹配 : 不可指定給較小的資料型態
    double ud=d;  //自動拆箱型態匹配
    System.out.println(ud);
    }
  }


可見, 因為 Integer 自動拆箱時會呼叫 intValue() 傳回 int 型態資料, 若指定給比 int 小的 byte 變數就會不匹配, 無法編譯成功. 同樣地, Double 自動拆箱時呼叫 doubleValue() 會傳回 double, 如果指定給 float 也會發生編譯錯誤.


沒有留言:

張貼留言