有時需要將 int 這樣的類型轉(zhuǎn)換為對象。所有的基本類型都有一個與之對應(yīng)的類。通常,這些類稱為包裝器(wrapper)。
這些對象包裝器類擁有顯而易見的名字:Integer、Long、Float、Double、Short、Byte、Character 和 Boolean (前 6 個類派生于公共的超類 Number)。
包裝器類是不可變的,即一旦構(gòu)造了包裝器,就不允許更改包裝在其中的值。同時,包裝器類還是 final,因此不能派生它們的子類。
假設(shè)想要定義一個整型數(shù)組列表。遺憾的是,尖括號中的類型參數(shù)不允許是基本類型,也就是說,不允許寫成 ArrayList<int>。這里就可以用到 Integer 包裝器類。我們可以聲明一個 Integer 對象的數(shù)組列表。
?ArrayList<Integer> list = new ArrayList<>();
警告: 由于每個值分別包裝在對象中,所以 ArrayList<lnteger> 的效率遠遠低于 int[] 數(shù)組。因此,只有當(dāng)程序員操作的方便性比執(zhí)行效率更重要的時候,才會考慮對較小的集合使用這種構(gòu)造。
幸運的是,有一個很有用的特性,從而可以很容易地向 ArrayLis<Integer> 添加 int 類型的元素。下面這個調(diào)用
?list.add(3);
將自動地變換成
?list.add(Integer.valueOf(3));
這種變換被稱為自動裝箱(autoboxing)。
當(dāng)將一個 Integer 對象賦給一個 int 值時,將會自動地拆箱。也就是說,編譯器將以下語句:
?int n = list.get(i);
轉(zhuǎn)換成
?int n = list.get(i).intValue();
自動地裝箱和拆箱甚至也適用于算術(shù)表達式。例如,可以將自增運算符應(yīng)用于包裝器引用:
Integer n = 3;
n++;
編譯器將自動地插入一條對象拆箱的指令,然后進行自增計算,最后再將結(jié)果裝箱。
大多數(shù)情況下容易有一種假象,認(rèn)為基本類型與它們的對象包裝器是一樣的。但它們有一點很大的不同:同一性。大家知道,== 運算符也可以應(yīng)用于包裝器對象,只不過檢測的是對象是否有相同的內(nèi)存位置,因此,下面的比較通常會失?。?/p>
Integer a = 1000;
Integer b = 1000;
System.out.println(a == 1000); // 一定為 true
System.out.println(a == b); // 通常為 false
不過,Java 實現(xiàn)卻有可能(如果選擇這么做)讓 a == b 為 true 成立。如果將經(jīng)常出現(xiàn)的值包裝到相同的對象中,這種比較就可能成功。這種不確定的結(jié)果并不是我們所希望的。解決這個問題的辦法是在比較兩個包裝器對象時調(diào)用 equals 方法。
注釋: 自動裝箱規(guī)范要求 boolean、byte、 char≤127,介于 -128 ~ 127 之間的 short和 int 被包裝到固定的對象中。例如,如果在前面的例子中將 a 和 b 初始化為 100,對它們進行比較的結(jié)果一定成功。
關(guān)于自動裝箱還有幾點需要說明。首先,由于包裝器類引用可以為 null,所以自動裝箱有可能會拋出一個 NullPointerException 異常:
Integer n = null;
System.out.print(n * n); // Throws NullPointerException
另外,如果在一個條件表達式中混合使用 Integer 和 Double 類型,Integer 值就會拆箱,提升為 double,再裝箱為 Double:
Integer n = 1;
Double x = 2.0;
System.out.println(true ? n : x); // prints 1.0
最后強調(diào)一下,裝箱和拆箱是編譯器要做的工作,而不是虛擬機。編譯器在生成類的字節(jié)碼時會插人必要的方法調(diào)用。虛擬機只是執(zhí)行這些字節(jié)碼。
使用數(shù)值包裝器通常還有一個原因。Java 設(shè)計者發(fā)現(xiàn),可以將某些基本方法放在包裝器中,這會很方便,例如,將一個數(shù)字字符串轉(zhuǎn)換成數(shù)值。
想要將字符串轉(zhuǎn)換成整數(shù),可以使用下面這條語句:
?int x = Integer.parselnt("100");
這里與 Integer 對象沒有任何關(guān)系,parselnt 是一個靜態(tài)方法。但 Integer 類是放置這個方法的一個好地方。
警告: 有些人認(rèn)為包裝器類可以用來實現(xiàn)修改數(shù)值參數(shù)的方法,然而這是錯誤的。由于 Java 方法參數(shù)總是按值傳遞,所以不可能編寫一個能夠增加整型參數(shù)的 Java 方法。
?public static void triple(int x) { // won't work
??x = 3 * x;
?}
將 int 替換成 Integer 又會怎么樣?
?public static void triple(Integer x) { // won't work
??x = 3 * x;
?}
問題是 Integer 對象是不可變的:包含在包裝器中的內(nèi)容不可變。不能使用這些包裝器類創(chuàng)建會修改數(shù)值參數(shù)的方法。
如果確實想編寫編寫一個修改數(shù)值參數(shù)的方法,可以使用 org.omg.CORBA 包中定義的某個持有者(holder) 類型,包括 IntHolder、BooleanHolder 等。每個持有者類型都包含一個公共(!)字段 value,通過它可以訪問存儲在其中的值。
?public static void triple(IntHolder x) {
??x.value = 3 * value;
?}
java.lang.Integer 1.0
- int intValue()
將這個 Integer 對象的值作為一個 int 返回(覆蓋 Number 類中的 intValue 方法)。
- static String toString(int i)
返回一個新的 String 對象,表示指定數(shù)值 i 的十進制表示。
- static String toString(int i, int radix)
返回數(shù)值 i 基于 radix 參數(shù)指定進制的表示。
- static int parseInt(String s)
返回字符串 s 表示的整數(shù),指定字符串必須表示一個十進制整數(shù)。
- static int parseInt(String s, int radix)
返回字符串 s 表示的整數(shù),指定字符串必須表示一個采用 radix 參數(shù)指定進制的整數(shù)。
- static Integer valueOf(String s)
返回一個新的 Integer 對象,采用字符串 s 表示的整數(shù)初始化。指定字符串必須表示一個十進制整數(shù)。
- static Integer valueOf(String s, int radix)
返回一個新的 Integer 對象,采用字符串 s 表示的整數(shù)初始化。指定字符串必須表示一個采用 radix 參數(shù)指定進制的整數(shù)。
java.text.NumberFormat 1.1
- Number parse(Sting s)
返回數(shù)字值,將設(shè)給定的 String 表示一個數(shù)值。