包裝類,拆箱、裝箱——一切皆對象
爲何要包裝類
- 在面向對象中,”一切皆對象”,但基本數據類型的特殊存在不太符合這一理念,面向對象面向得並不純粹,因爲基本類型變量並不是對象;
- 涉及進制間的轉換的算法,數據類型間的基本操作;如果都要我們來實現,那工作量就太大了;
- 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中,基本類型變量存儲在棧中的,而包裝類型對象存放於堆中。
其實,包裝類就是把基本數據類對象化,包裝類是基本數據類型的超集;在開發中,建議成員變量優先使用包裝類型,局部變量優先考慮基本數據類型。
完結。老夫雖不正經,但老夫一身的才華