【java基礎(二十九)】對象包裝器與自動裝箱

有時,需要將Int這樣的基本類型轉換爲對象。所有的基本類型都有一個與之對應的類。例如,Integer類對應基本類型int。通常,這些類稱爲包裝器(wrapper)。這些對象包裝器類擁有很明天的名字:Integer、Long、Float、Double、Short、Byte、Character、Void和Boolean(前6個類派生於公共的超類Number)。對象包裝器類是不可變的,即一旦構造了包裝器,就不允許改變包裝在其中的值。同時,對象包裝器類還是final,因此不能定義它們的子類。
假設想定義一個整型數組列表。而尖括號中的類型參數不允許是基本類型,也就是說,不允許寫成ArrayList。這裏就用到了Integer對象包裝器。我們可以聲明一個Integer對象的數組列表。

ArrayList<Integer> list = new ArrayList<>();

注意:由於每個值分別包裝在對象中,所以ArrayList<Integer>的效率遠遠低於int[]數組。因此,應該用它構造小型集合,其原因是此時程序員操作的方便性要比執行效率更加重要。
幸運的是,有一個很有用的特性,從而更加便於添加int類型的元素到ArrayList<Integer>中。如:

list.add(3);

將自動地變換成

list.add(Integer.valueOf(3));

這種變換稱爲自動裝箱(autoboxing)。
相反的,當將一個Integer對象賦給一個int值時,將會自動的拆箱。也就是說,編譯器將下列語句:

int n = list.get(i);

翻譯成

int n = list.get(i).intValue();

甚至在算術表達式中也能夠自動地裝箱和拆箱。例如:可以將自增操作符應用於一個包裝器引用:

Integer n = 3;
n++;

編譯器將自動地插入一條對象拆箱的指令,然後進行自增計算,最後再將結果裝箱。
大多數情況下,容易有一種假象,即基本類型與它們的對象包裝器是一樣的,只是它們的相等性不同。大家知道,==運算符也可以應用於對象包裝器對象,只不過檢測的是對象是否指向同一個存儲區域,因此,下面的比較通常不會成立:

Integer a = 1000;
Integer b = 1000;
if (a == b) ...

然而,Java實現卻有可能讓他成立。如果將經常出現的值包裝在同一個對象中,這種比較就有可能成立。這種不確定的結果並不是我們所希望的。解決這個問題的方法就是在兩個包裝器對象比較時調用equals方法。
關於自動裝箱還有幾點需要說明。首先,由於包裝器類引用可以爲null,所以自動裝箱有可能會拋出一個NullPointerException異常:

Integer n = null;
System.out.println(2 * n); // 拋空指針異常

另外,如果在一個條件表達式中混合使用Integer和Double類型,Integer值就會拆箱,提升爲double,在裝箱爲Double:

Integer n = 1;
Double x = 2.0;
System.out.println(true ? n : x); // 1.0

最後強調一下,裝箱和拆箱是編譯器認可的,而不是虛擬機。編譯器在生成類的字節碼時,插入必要的方法調用。虛擬機只是執行這些字節碼。
使用數值對象包裝器還有另外一個好處。Java設計者發現,可以將某些基本方法放置在包裝器中,例如,將一個數字字符串換成數值。
想要將字符串轉換成整型,可以使用下面這條語句:

int x = Integer.parseInt(s);

這裏與Integer對象沒有任何關係,parseInt是一個靜態方法。但Integer類是放置這個方法的一個好地方。

捐贈

若你感覺讀到這篇文章對你有啓發,能引起你的思考。請不要吝嗇你的錢包,你的任何打賞或者捐贈都是對我莫大的鼓勵。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章