Java自動裝箱與拆箱及其陷阱分析

Java中一個非常重要也非常有趣的特性,就是自動裝箱與拆箱,本文是本站小編搜索整理的關於Java自動裝箱與拆箱及其陷阱分析,給大家做個參考,希望對大家有所幫助!想了解更多相關信息請持續關注我們應屆畢業生考試網!

Java自動裝箱與拆箱及其陷阱分析
  自動裝箱(Autoboxing)

  定義

大家在平時編寫Java程序時,都常常以以下方式來定義一個Integer對象:

Integer i=100;

從上面的代碼中,大家可以得知,i爲一個Integer類型的引用,100爲Java中的基礎數據類型(primitive data type)。而這種直接將一個基礎數據類型傳給其相應的封裝類(wrapper class)的做法,便是自動裝箱(Autoboxing)。

在jdk 1.5中,自動裝箱首次被引入。而在jdk 1.5之前,如果你想要定義一個value爲100的Integer對象,則需要這樣做:

Integer i=new Integer (100);

  原理

我們在以上代碼“Integer i=100;”處打一個斷點,跟蹤一下。

接下來,我們可以看到,程序跳轉到了Integer類的valueOf(int i)方法中

/**

* Returns a <tt>Integer</tt> instance representing the specified

* <tt>int</tt> value.

* If a new <tt>Integer</tt> instance is not required, this method

* should generally be used in preference to the constructor

* {@link #Integer(int)}, as this method is likely to yield

* significantly better space and time performance by caching

* frequently requested values.

*

* @param i an <code>int</code> value.

* @return a <tt>Integer</tt> instance representing <tt>i</tt>.

* @since 1.5

*/

public static Integer valueOf(int i) {

if(i >= -128 && i <= )

return e[i + 128];

else

return new Integer(i);

}

換句話說,裝箱就是jdk自己幫你完成了調用eOf(100)。

  拆箱(Unboxing)

  定義

Integer integer100=100;

int int100=integer100;

從上面的代碼中,大家可看出integer100爲一個Integer類型的引用,int100爲一個int類型的原始數據類型。但是,我們可以將一個Integer類型的對象賦值給其相應原始數據類型的變量。這便是拆箱。

拆箱與裝箱是相反的操作。裝箱是將一個原始數據類型賦值給相應封裝類的變量。而拆箱則是將一個封裝類的變量賦值給相應原始數據類型的變量。裝箱、拆箱的名字也取得相當貼切。

  原理

筆者相信大家也都猜到了,拆箱過程中jdk爲我們做了什麼。我們還是通過實驗來證明我們的猜想吧。

在以上代碼的第二行代碼打上斷點,即在“int int100=integer100;”上打上斷點,跟蹤一下。

我們可以看到,程序跳轉到了Integer的intValue()方法。

/**

* Returns the value of this <code>Integer</code> as an

* <code>int</code>.

*/

public int intValue() {

return value;

}

也就是,jdk幫我們完成了對intValue()方法的.調用。對於以上的實驗而言,便是調用integer100的intValue()方法,將其返回值賦給了int100。

  擴展

  實驗1

Integer integer400=400;

int int400=400;

tln(integer400==int400);

在以上代碼的第三行中,integer400與int400執行了==運行。而這兩個是不同類型的變量,到底是integer400拆箱了,還是int400裝箱了呢?運行結果是什麼呢?

==運算是判斷兩個對象的地址是否相等或者判斷兩個基礎數據類型的值是否相等。所以,大家很容易推測到,如果integer400拆箱了,則說明對比的是兩個基礎類型的值,那此時必然相等,運行結果爲true;如果int400裝箱了,則說明對比的是兩個對象的地址是否相等,那此時地址必然不相等,運行結果爲false。(至於爲什麼筆者對它們賦值爲400,就是後面將要講到的陷阱有關)。

我們實際的運行結果爲true。所以是integer400拆箱了。對代碼跟蹤的結果也證明這一點。

  實驗2

Integer integer100=100;

int int100=100;

tln(ls(int100));

在以上代碼的第三行中,integer100的方法equals的參數爲int100。我們知道equals方法的參數爲Object,而不是基礎數據類型,因而在這裏必然是int100裝箱了。對代碼跟蹤的結果也證明了這一點。

其實,如果一個方法中參數類型爲原始數據類型,所傳入的參數類型爲其封裝類,則會自動對其進行拆箱;相應地,如果一個方法中參數類型爲封裝類型,所傳入的參數類型爲其原始數據類型,則會自動對其進行裝箱。

  實驗3

Integer integer100 = 100;

int int100 = 100;

Long long200 = 200l;

tln(integer100 + int100);

tln(long200 == (integer100 + int100));

tln(ls(integer100 + int100));

在第一個實驗中,我們已經得知,當一個基礎數據類型與封裝類進行==運算時,會將封裝類進行拆箱。那如果+、-、*、/呢?我們在這個實驗中,就可知道。

如果+運算,會將基礎數據類型裝箱,那麼:

?第4行中,integer100+int100就會得到一個類型爲Integer且value爲200的對象o,並執行這個對象的toString()方法,並輸出”200”;

?第5行中,integer100+int100就會得到一個類型爲Integer且value爲200的對象o,==運算將這個對象與long200對象進行對比,顯然,將會輸出false;

?第6行中,integer100+int100就會得到一個類型爲Integer且value爲200的對象o,Long的equals方法將long200與o對比,因爲兩都是不同類型的封裝類,因而輸出false;

如果+運算,會將封裝類進行拆箱,那麼:

?第4行中,integer100+int100就會得到一個類型爲int且value爲200的基礎數據類型b,再將b進行裝箱得到o,執行這個對象的toString()方法,並輸出”200”;

?第5行中,integer100+int100就會得到一個類型爲int且value爲200的基礎數據類型b1,==運算將long200進行拆箱得到b2,顯然b1==b2,輸出true;

?第6行中,integer100+int100就會得到一個類型爲int且value爲200的基礎數據類型b,Long的equals方法將b進行裝箱,但裝箱所得到的是類型爲Integer的對象o,因爲o與long200爲不同的類型的對象,所以輸出false;

程序運行的結果爲:

200

true

false

因而,第二種推測是正確,即在+運算時,會將封裝類進行拆箱。