目錄html
學習了許久的Java,咱們知道Java是一種面向對象的語言,萬物皆對象。可是咱們以前在說到Java基本數據類型的時候,因爲處理對象須要額外的系統開銷,因而出於對性能的考慮,基本數據類型並不作爲對象使用。
既然是面向對象的,在Java中許多方法須要把對象做爲參數,可是基本類型變量身上沒有任何方法和屬性,因而Java提供了一個簡單的方法,就是爲每個基本數據類型類型都配套提供一個包裝類型,咱們即可以在二者之間來回反覆地橫跳。java
先看一波包裝類型的繼承圖:
緩存
數值類型都直接繼承於父類Number類,非數值類型Character和Boolean直接繼承於Object類。工具
除此以外,包裝類型的名字也很是好記,除了int->Integer
和char->Character
兩個比較特殊以外,其餘都是基本數據類型的首字母改成大寫便可,如:byte->Byte
。性能
經過查看官方文檔,咱們能夠發現,數值類型繼承的Number類實際上是一個抽象類,那麼可想而知,該類中的抽象方法已經在這幾個數值類型中獲得實現,看一波:
學習
很明顯,除了最後一個serialVersionUID(這個之後再總結),其餘的方法在數值型包裝類中都存在,能夠經過這些方法將對象「轉換」爲基本類型的數值。this
咱們再來看看包裝類型的構造器,咱們再查看全部包裝類以後,發現:.net
Integer i1 = new Integer(5);//5 Integer i2 = new Integer("5");//5
this.value = value
,一目瞭然。public Integer(String s) throws NumberFormatException { this.value = parseInt(s, 10); }
深究一下,parse(String s,int radix)中的radix其實表明着進制信息,而咱們的構造器默認讓radix爲10,表明着輸出字符串s在十進制下的數,因此除了數字0-9以外,字符串中不能有其餘的玩意兒,不然會拋出NumberFormatException的異常。debug
咱們在上面說過,基本數據類型和包裝類型之間的轉換涉及到裝箱與拆箱的操做,爲了簡化代碼,在JDK1.5以後,Java容許基本類型和包裝類型之間能夠自動轉換。指針
將基本類型直接賦值給對應的引用類型,編譯器在底層自動調用對應的valueOf方法。
就像下面這樣:
int i = 5; Integer in = i;
咱們利用debug調試工具設上斷點,發如今執行Integer in = i;
時,將會自動調用下面的方法:
繼續深究其底層實現,咱們發現IntegerCache實際上是Integer包裝類的一個內部類,咱們進入IntegerCache一探究竟:
咱們會發現全部的整數類型的(包括Character)包裝類裏都有相似的玩意兒,因此大體運行的規則應該大體相同,在這裏就總結幾點不太同樣的:
int num = 100; Integer i1 = num; Integer i2 = num; System.out.println(i1==i2);//true //num改成200,結果爲false
Integer i1 = 100; Integer i2 = new Integer(100); System.out.println(i1 == i2);//false
將引用類型字節賦值給對應的基本類型,編譯器在底層自動調用對應的xxxvalue方法(如intValue)。
Integer in = 5; int i = in;
自動拆箱相對來講就稍微簡單一點了,咱們仍是利用debug工具,發現上面的代碼將會自動調用下面的方法
int num = 100; Integer i1 = num; Integer i2 = num; //都是包裝器類型的引用時,比較是否指向同一對象。 System.out.println(i1==i2);//true Integer i1 = 128; int i2 = 128; //若是包含算數運算符,則底層自動拆箱,即比較數值。 System.out.println(i1 == i2);//true Integer i3 = 1; Integer i4 = 129; System.out.println(i4 == i1+i3);//true
equals比較的是同一包裝類型,即比較二者數值是否相等
Integer i1 = 5; Integer i2 = 5; Integer i3 = 10; //同一包裝類型,比較數值是否相等 System.out.println(i1.equals(i2));//true System.out.println(i3.equals(i1+i2));//true Long l1 = 5L; Long l2 = 10L; //Long與Integer比較,不是同一類型,false System.out.println(l1.equals(i1));//false //先自動拆箱,i1先轉爲int,l轉爲long,int自動類型提高轉爲long,最後相等 System.out.println(l2.equals(l1+i1));//true
Integer sum = 0; for(int i = 500;i<5000;i++){ //先自動拆箱,然後自動裝箱 sum+=i; }
在拆箱裝箱操做以後,因爲sum數值超過緩存範圍,因此會new出4500個毫無用處的實例對象,大大影響了程序的性能。因此在循環語句以前,務必聲明正確的變量類型。
private static Integer sum; public static void setSum(Integer num,boolean flag){ sum = (flag)?num:-1; }
上面的代碼,當num傳入爲null時,即會引起空指針異常,由於包裝類在進行算術運算時(上述是三目運算),若是數據類型不一致,將會先自動拆箱轉換成基本類型進行運算,而null若是調用了intValue()方法就會造成空指針。
改進方案:
public static void setSum(Integer num,boolean flag){ //這樣類型一致,便不會自動拆箱了 sum = (flag)?num:Integer.valueOf(-1); }
參考連接: