上一節咱們講解了StringBuilder VS StringBuffer以及兩者區別,本節咱們來說解包裝類。java
咱們知道在Java中有8中基本數據類型,分爲數值類型:byte、short、int、long、float、double。字符類型:char。布爾類型:bool,那麼什麼是包裝類呢?包裝類是8種基本數據類型的對象表示,並且8種包裝類和字符串對象同樣是不可變且final(不可經過繼承或擴展破壞不可變性)的。咱們經過查看int的包裝類型Integer可知,以下:編程
以下爲基本數據類型對應的包裝類以及構造函數參數:緩存
基本數據類型 | 包裝類型 | 構造參數 |
---|---|---|
byte | Byte | byte or String |
short | Short | short or String |
int | Integer | int or String |
long | Long | long or String |
float | Float | float, double or String |
double | Double | double or String |
char | Character | char |
boolean | Boolean | boolean or String |
好比當咱們實例化Integer包裝類時,既然是對int的包裝,要是咱們傳一個帶小數位的數字,毫無疑問也就拋出以下異常了:安全
public class Main { public static void main(String[] args) { Integer a = new Integer("12.5"); } }
開頭咱們就直接拋出了包裝類的概念,可是不知道您是否有和我同樣的疑惑,咱們爲何要用包裝類呢?好比Integer是對int的包裝,咱們直接使用int不就完事了嗎,怎麼還包裝一層呢?這就須要咱們瞭解包裝類的做用是什麼了?數據結構
1.包裝類將基本數據類型轉換爲對象(當咱們須要在給定方法中傳遞參數時須要對象)。多線程
2.包java.util只處理對象的類,因此包裝類在這個包中也有其用武之地。app
3.數據結構僅存儲對象和基本數據類型。編程語言
4.在多線程中,咱們須要對象來支持線程同步。函數
或者說存在即合理,在Java中將包裝類和基本數據類型區分開這是明智之舉,當咱們以適合面向對象的方式編程時,咱們使用包裝類,當處理起來更加簡單時,咱們使用基本數據類型,一切取決於咱們。ui
在Java 5中引入了自動裝箱和拆箱,這容許基本數據類型和包裝類相互之間可以輕鬆自如的實現轉換。接下來咱們經過基本數據類型和包裝類轉換實現裝箱和拆箱,裝箱則是自動將基本數據型轉換爲包裝類,拆箱反之。
char ch = 'a'; Character a = ch; ArrayList<Integer> arrayList = new ArrayList<Integer>(); arrayList.add(25); System.out.println(arrayList.get(0));
如上第一個咱們將基本數據類型轉換爲對象以及咱們初始化集合且參數類型爲包裝類(對象),緊接着咱們在此集合中添加基本數據類型爲25的int,都自動實現了裝箱。反過來,以下咱們將實現拆箱:
Character ch = 'a'; char a = ch; ArrayList<Integer> arrayList = new ArrayList<Integer>(); arrayList.add(24); int num = arrayList.get(0); System.out.println(num);
上述咱們首先將包裝類轉換爲基本數據類型,緊接着咱們添加基本數據類型爲24的int,這屬於裝箱,可是最後咱們獲取數據時賦值給爲int的num,也就達到了將包裝類到基本數據類型的轉換,也就是拆箱。同時咱們還需謹記:包裝類能夠爲空,基本數據類型不能爲空。也就是說要使其可空,咱們必須使用包裝類,這一點比不上C#語法高級,若基本數據類型可空,在C#中可以下定義:
int? a = null;
Console.WriteLine(a == null);
接下來咱們來看以下一道題,請問:以下是自動裝箱嗎?若是不是體現了什麼呢?
public class Main { public static void main(String[] args) { char c = 'a'; doSomething(new Character(c)); } static void doSomething(Object obj) { } }
咱們知道自動裝箱是將基本數據類型轉換爲包裝類,上述咱們定義了一個doSomething方法,參數爲Object類型,在程序入口點,咱們調用該方法且傳入的參數爲包裝類,因此上述並非自動裝箱,它所體現的是經過包裝類實現多態。因此咱們需謹記:自動裝箱是將基本數據類型轉換爲包裝類,而不是將一種數據類型轉換爲其餘數據類型,這也許就是爲何自動裝箱不能將String轉換爲包裝類的緣由。
咱們依然以基本數據類型int爲例,在int對應的包裝類Integer中有intValue方法實現拆箱,好比咱們想要將double轉換爲int,利用包裝類實現則是以下形式:
double d = 135.d;
Double doubleWrapper = new Double(d); int integerValue = doubleWrapper.intValue(); System.out.println(integerValue);
咱們也可使用包裝類類型經過拆箱轉換成其餘基本數據類型,當咱們須要將基本數據類型轉換爲對象並使用它們來獲取其餘基本數據類型時,將使用這種類型的轉換。經過如上轉換,咱們須要編寫一大片代碼, 然而,咱們能夠經過以下簡單的方式來實現相同的目的:
double d = 135.d;
int integerValue = (int)d; System.out.println(integerValue);
到目前我所知道的有如下兩種方式將String對象轉換爲int或Integer,咱們一塊兒來看看。
此種方式做爲將String轉換爲int的首先方式,簡單且靈活,咱們看一個例子:
int i = Integer.parseInt("123");
System.out.println("i: " + i);
若是提供的String不是正確的數字,Integer.parseInt()方法將拋出NumberFormatException異常,相同的方式一樣適用於其餘數據類型(如float和Double)轉換爲Java中的String。 Java API提供靜態方法,如Float.parseFloat()和Double.parseDouble(),以執行數據類型轉換。
在8種包裝類中都有這個valueOf方法,這也是一種將String轉換爲int的方式,咱們一樣來看一個示例:
int i = Integer.valueOf("000000081");
System.out.println("i: " + i);
它將忽略前導零並將字符串轉換爲int。若是提供的String不是正確的數字,一樣也會拋出NumberFormatException異常。在Java 1.4以前沒有自動裝箱,可是在Java 1.5即(Java 5+)引入了自動裝箱,因此推薦使用Integer.valueOf(int)而不是new Integer(int),由於Integer如今能夠在-128到127之間緩存Integer對象,而且每次均可以將同一個完整的Integer(0)對象交給咱們,而不是在全新的相同Integer對象上浪費對象構造。
下面咱們來看兩個例子來驗證上述源碼觀點:
Integer i1 = 260;
Integer i2 = 260; if (i1 == i2) { System.out.println("i1 and i2 is equal"); } else { System.out.println("i1 and i2 is not equal "); }
接下來咱們再來看一個例子,以下:
Integer i1 = 100;
Integer i2 = 100; if (i1 == i2) { System.out.println("i1 and i2 is equal"); } else { System.out.println("i1 and i2 is not equal "); }
咱們看到「i1和i2相等」,由於-128到127之間的int值在大多數JVM要緩存的範圍內,因此VM實際上對i1和i2使用相同的對象實例(所以也使用同一內存地址),因此打印出相等。Integer.valueOf方法還有重載,咱們來看一個例子:
Integer I = Integer.valueOf("100", 2);
System.out.println(I);
Integer i = Integer.valueOf("101", 4); System.out.println(i);
第二個參數表示進制,例如上述兩個經過2進製表示100,經過4進製表示101,計算方式以下:
2進製表示100:(1 * 2 ^ 2)+(0 * 2 ^ 1)+(0 * 2 ^ 0)= 4 + 0 + 0 = 4。
4進製表示101:(1 * 4 ^ 2)+(0 * 4 ^ 1)+(1 * 4 ^ 0)= 16 + 0 + 1 = 17。
valueOf和parseInt方法都用於在Java中將String轉換爲Integer,但它們之間存在細微差異(在Java 1.5引入自動裝箱後),咱們經過查看valueOf()方法的源碼得知,發現它在內部調用parseInt()方法將String轉換爲Integer,可是它還維護一個從-128到127的整數池,若是請求的整數在池中,它從池中返回對象,這也意味着使用valueOf()方法返回的兩個整數對象能夠經過相等運算符相同,這種對不可變對象的緩存,確實有助於減小垃圾並幫助垃圾收集器。 parseInt()和valueOf()方法之間的另外一個區別是返回類型,valueOf()返回一個Integer對象,而parseInt()方法返回一個int基本數據類型。不管是使用parseInt仍是valueOf將String轉換爲基本數據類型Int和包裝類Integer,若是咱們須要基本數據類型Int可使用parseInt,因爲不可變對象能夠安全地緩存在池中而且獲得重用,如此一來減小了垃圾收集器的負載,所以若是須要Integer對象,最好使用valueOf。
Java中的「==」或等於運算符是Java編程語言提供的二元運算符,用於比較基元和對象,在比較boolean,int,float等基本數據類型時,利用「==」工做正常,但在比較對象時,它會與Java中的equals方法產生混淆, 「==」根據內存引用比較兩個對象。 因此「==」運算符只有在兩個對象引用比較時才返回true來表示徹底相同的對象,不然「==」將返回false。在Java 5中引入自動裝箱和拆箱以後,因版本的問題使用「==」來比較包裝器對象可能會出現意想不到的結果。