包裝類,拆箱、裝箱——一切皆物件
為何要包裝類
- 在物件導向中,”一切皆物件”,但基本資料型別的特殊存在不太符合這一理念,物件導向面向得並不純粹,因為基本型別變數並不是物件;
- 涉及進位制間的轉換的演算法,資料型別間的基本操作;如果都要我們來實現,那工作量就太大了;
- Java的集合框架並不支援基本資料型別的儲存,只支援物件儲存;
故此,針對Java基本資料型別封裝了包裝類,每一個基本型別都有一個對應的包裝類,以下是詳情:
八大基本資料型別的包裝類都使用final修飾,都是最終類,都不能被繼承。
// Byte
public final class Byte extends Number implements Comparable<Byte> { }
// Character
public final class Character implements java.io.Serializable, Comparable<Character> { }
// Short
public final class Short extends Number implements Comparable<Short> { }
// Integer
public final class Integer extends Number implements Comparable<Integer> { }
// Long
public final class Long extends Number implements Comparable<Long> { }
// Float
public final class Float extends Number implements Comparable<Float> { }
// Double
public final class Double extends Number implements Comparable<Double> { }
// Boolean
public final class Boolean implements java.io.Serializable, Comparable<Boolean> { }
複製程式碼
拆箱和裝箱
裝箱:把基本型別資料轉成對應的包裝類物件。
方式一:
Integer i = Integer.value(13);
複製程式碼
方式二:
Integer i = new Integer(13);
複製程式碼
拆箱:把包裝類物件轉成對應的基本資料型別資料。
int value = i.intValue();
複製程式碼
自動裝箱(Autoboxing)和自動拆箱(AutoUnboxing)
在Java 5之前的版本中,基本資料型別和包裝類之間的轉換是需要手動進行的,但Sun公司從Java5開始提供了的自動裝箱(Autoboxing)和自動拆箱(AutoUnboxing)操作 ;
- 自動裝箱:可以把一個基本型別變數直接賦給對應的包裝型別變數。
Integer i = 13;
複製程式碼
- 自動拆箱:允許把包裝類物件直接賦給對應的基本資料型別變數。
Integer i = new Integer(13);
Int j = i;
複製程式碼
自動裝箱和自動拆箱,也是一個語法糖/編譯器級別新特性,在底層依然是手動裝箱、拆箱操作;但是在裝箱操作中使用的是Integer.valueOf()方法,而不是直接new Integer();其他的幾個包裝類也是如此,裝箱操作中使用的是各自的valueOf()方法。
switch 對包裝類的支援
switch支援的基本資料型別:byte,short,char,int;也支援對應的包裝類。因為在底層,switch中會對包裝類做手動拆箱操作。
考慮下面的語句:
Object obj = 17;
複製程式碼
在上述程式碼語句中有如下的操作:
- 自動裝箱: Integer i = 17;
- 引用的自動型別轉換,把子類物件賦給父類變數: Object obj = i; 因為Object類的父類;
因此,Object可以接受一切資料型別的值;Object陣列:Object[]該陣列可以裝一切資料型別。
Object\[\] arr = {“A”,12,3.14,true}; // 這是完全可行的
複製程式碼
包裝類的常用操作方法(以Integer為例):
1. 包裝類中的常量:
- MAX_VALUE :最大值
- MIN_VALUE :最小值
- SIZE :變數在記憶體中儲存資料佔多少位
- TYPE :對應的基本型別
2. 包裝類的構造器:建立包裝類物件,
/\*\* Integer 構造器原始碼 \*\*/
// 接收int型別資料構建Integer物件
public Integer(int value) {
this.value = value;
}
// 接受字串資料構建Integer物件
public Integer(String s) throws NumberFormatException {
this.value = parseInt(s, 10);
}
複製程式碼
其他的幾個包裝型別也是這樣的規律,具體實現檢視原始碼即可。
3. 基本型別和包裝型別的轉換(裝箱和拆箱)
裝箱:
Integer i1 = new Integer(13); // 方式一,每次都會建立新物件,不推薦
Integer i2 = Integer.valueOf(13); // 方式二,推薦,底層使用了快取。
複製程式碼
拆箱:
int val = i1.intValue();
複製程式碼
4. String和基本型別/包裝型別之間的轉換操作
把String轉換為包裝類型別:
方式1:包裝類.valueOf(String str):
Integer i = Integer.valueOf(“13”);
方式2: new 包裝類(String str):
Integer i= new Integer(“13”);
複製程式碼
把包裝類物件轉換為String.
String str = 物件.toString(); // 不止包裝類物件,其他任何物件都可以使用toString()轉換;
複製程式碼
把基本資料型別轉換為String:
String str = 13 + "";
複製程式碼
把String轉換為基本資料型別:
parseXxx(String s) : xxx表示8大基本資料型別,如:
String input=”12345”;
int value = Integer.parseInt(input);
複製程式碼
5. 對於Boolean來說,無論是使用new Boolean(“”); 還是Boolean.valueOf(“”), 只有使用true/TRUE會被認為是true,其他都是false。
Boolean b1 = new Boolean("true"); // true
Boolean b1 = new Boolean("TRUE"); // true
Boolean b1 = new Boolean("sjsj"); // false
複製程式碼
包裝類中的快取設計
在包裝類中提供了快取設計,會對一定範圍內的資料作快取,如果資料在範圍內,會優先從快取中取資料,超出範圍才會建立新物件;Byte、Short、Integer、Long:快取[-128,127]區間的資料;Character:快取[0,127]區間的資料;包裝類中的快取設計,也稱為享元模式。
快取設計會在包裝類中的valueOf()方法中實現,所以才會推薦使用valueOf()方法來實現拆箱操作,如下是Integer類的valueOf()原始碼:
再檢視快取實現細節:
通過檢視原始碼可知,JVM會對-128 到 127之間的做快取,如果你的變數值在這個範圍內,就會優先從快取中取資料,否則就會建立新物件。當然這個快取區間也是可是設定的。
那麼以下這個例子就可以解釋了:
public static void main(String\[\] args) {
Integer i1 = Integer.valueOf(13);
Integer i2 = Integer.valueOf(13);
System.out.println(i1 == i2);
// 輸出為true。因為13在\[-128, 127\]之間,但是並沒有建立新物件
Integer i3 = Integer.valueOf(129);
Integer i4 = Integer.valueOf(129);
System.out.println(i3 == i4);
// 輸出為false, 因為129不在\[-128, 127\]之間,是使用new Integer()建立了新物件,故比較為false
Integer i5 = 129;
Integer i6 = 129;
System.out.println(i5 == i6); // 輸出為false
System.out.println(i5.equals(i6));
// 輸出為true,建議:如果物件包裝類物件的值作比較,應選用包裝類的equals方法。
}
複製程式碼
我們再來看Integer的equals方法的實現原始碼:
可以發現,包裝類在比較時會將包裝型別拆箱為基本資料型別,並使用==做比較。
包裝型別和基本資料型別的區別
包裝型別和基本資料型別的區別(以Integer與int的區別為例):
1. 預設值:
- int的預設值是0。
- Integer的預設值為null。Integer既可以表示null,又可以表示0。
2. 包裝類中提供了該型別相關的很多演算法操作方法:
* static String toBinaryString(int i) :把十進位制轉換為二進位制
* static String toOctalString(int i) : :把十進位制轉換為八進位制
* static String toHexString(int i) : :把十進位制轉換為十六進位制
複製程式碼
3. 在集合框架中,只能儲存物件型別,不能儲存基本資料型別值。
4. Integer和int並不是相同的資料型別,儘管值是相同的。Integer是一個類,可以例項化為物件,但int只是一個基本資料型別。
5. 在JVM中,基本型別變數儲存在棧中的,而包裝型別物件存放於堆中。
其實,包裝類就是把基本資料類物件化,包裝類是基本資料型別的超集;在開發中,建議成員變數優先使用包裝型別,區域性變數優先考慮基本資料型別。
完結。老夫雖不正經,但老夫一身的才華