為何要包裝類
- 在面向對象中,”一切皆對象”,但基本數據類型的特殊存在不太符合這一理念,面向對象面向得並不純粹,因為基本類型變量並不是對象;
- 涉及進制間的轉換的算法,數據類型間的基本操作;如果都要我們來實現,那工作量就太大了;
- Java的集合框架並不支持基本數據類型的存儲,只支持對象存儲;
故此,針對Java基本數據類型封裝了包裝類,每一個基本類型都有一個對應的包裝類,以下是詳情:
八大基本數據類型的包裝類都使用final修飾,都是最終類,都不能被繼承。
// Byte
public final class Byte extends Number implements Comparable<byte> { }/<byte>
// Character
public final class Character implements java.io.Serializable, Comparable<character> { }/<character>
// Short
public final class Short extends Number implements Comparable<short> { }/<short>
// Integer
public final class Integer extends Number implements Comparable<integer> { }/<integer>
// Long
public final class Long extends Number implements Comparable<long> { }/<long>
// Float
public final class Float extends Number implements Comparable<float> { }/<float>
// Double
public final class Double extends Number implements Comparable<double> { }/<double>
// Boolean
public final class Boolean implements java.io.Serializable, Comparable<boolean> { }/<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;
在上述代碼語句中有如下的操作:
1):自動裝箱: Integer i = 17;
2):引用的自動類型轉換,把子類對象賦給父類變量: 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中,基本類型變量存儲在棧中的,而包裝類型對象存放於堆中。
其實,包裝類就是把基本數據類對象化,包裝類是基本數據類型的超集;在開發中,建議成員變量優先使用包裝類型,局部變量優先考慮基本數據類型。
完結。
閱讀更多 老夫不正經 的文章