JAVA中的自動裝箱/拆箱

前言:自動裝箱和拆箱是JDK1.5提供的新特性,大致是由編譯器自動幫助完成基本類型和基本類型的包裝類之間的轉換。

好吧,知道了自動裝箱的大致意思之後,我們先來複習一個有關基本類型以及包裝類的概念:

基本類型:int,double,float,long,boolean,char,btye,short

基本類型包裝類:Integer,Double,Float,Long,Boolean,Char,Byte,Short

兩者有什麼差別,包裝類是類,是對象,而基本類型是有值的“變量”,再細化一點,就是包裝類的實例(對象)創建在堆上,而基本類型創建在棧上,這是JAVA爲了程序的速度考慮做出的優化,那麼既然是創建在棧上,所以基本類型都有大小的規定(每種基本類型所佔的字節是一定的)。

扯句題外話,那麼爲什麼java的設計者要設計出包裝類呢?我的理解是既然java作爲一門面向對象的語言,那麼包裝類作爲類,可以容納更多的信息,可以提供更多的操作。另外,包裝類都實現了Comparable接口,可以實現對象之間的比較,所以包裝類之間的比較儘量用compareTo,而不是><=這些運算符。切記。

在JDK1.5之前,我們要實現基本類型和包裝類之間的轉換,大多是通過包裝類提供的方法,Integer i = Integer.valueOf(5)或者int j = i.intValue()來做互相轉換的。JDK1.5之後,編譯器會在我們做賦值操作(這裏所說的賦值操作不包括構造函數,我們後面會講)的時候幫我們自動完成基本類型和包裝類之間的相互轉換。

上面我們所說的賦值操作,基本上可以分爲兩種情況,一種是顯式賦值,另一種是隱式賦值:

顯式賦值,我們可以理解爲有賦值符號出現的情況,比如,Integer i = 11;這裏編譯器會自動的幫你完成把11這個int的基本類型裝箱成包裝類實例的工作,這樣就不用我們再手動的轉換了。

隱式賦值,就是沒有複製符號出現的情況,這點我們很多人經常忽略,比如方法調用時候的參數傳遞,比如我們有一個接受Integer類型參數的方法(void method(Integer i)),我們在調用的時候可以直接傳遞一個基本類型的實參進去(method(5)),這時候編譯器會自動的將我們傳遞進去的實參裝箱成包裝類,從而完成對方法的調用。很簡單的一個過程,裏面的原理卻不簡單,這是因爲,方法調用的時候,在內存中的棧上,首先會爲方法的形參創建內存區域,然後將我們傳遞進去的實參賦值給形參,看到沒,就是在這時,發生了賦值操作,纔會讓編譯器完成裝箱操作。當然,方法執行完後,棧上有關形參的內存區域會被回收。

還有我們要記住一點,就是編譯器的裝箱/拆箱原則,就是基本類型可以先加寬(比如int轉換爲long),再轉變成寬類型的包裝類(Long),但是不能轉變成寬類型的包裝類型。

比如我們有個方法 void method(long l),我們通過method(5)是可以調用該方法的,因爲int類型的5被加寬成了long類型;但是如果這個方法變成void method(Long l),我們通過method(5)就不能調用它了,因爲int類型的5是不能直接轉換成Long包裝類的。切記。

最後還有一個值得注意的地方,就是上面我們提到的顯示賦值的情況下,比如Integer i = 11的情況,實際上在源碼中是調用到了Integer的靜態方法valueOf(),在這一塊,java的設計者採用了cache pool的設計模式,在Integer這個類裏面有一個長度爲256的靜態Integer數組,裏面存儲了從-128到127的Integer對象,當我們傳遞進去的參數在這個範圍之內時,這個方法會返回該數據中實現保存的Integer對象實例,只有超過該範圍時,纔會返回new出來的Integer對象實例。

[java] view plaincopy
  1. public static Integer valueOf(int i) {  
  2.     return  i >= 128 || i < -128 ? new Integer(i) : SMALL_VALUES[i + 128];  
  3. }  


所以會出現下面代碼的情況:

[java] view plaincopy
  1. Integer i = Integer.valueOf(124);  
  2. Integer j = Integer.valueOf(124);  
  3. System.out.printIn("result 1:" + (i==j));  
  4. Integer x = Integer.valueOf(266);  
  5. Integer y = Integer.valueOf(266);  
  6. System.out.println("result 2:" + (x==y));  
  7. 結果:result 1:true  
  8.          result 2:false  

PS:==符號比較的基本類型的值,對對象類型而言,比較的是對象的內存地址。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章