Java--裝箱和拆箱詳解
裝箱
八大基本類型都有一個與之對應的類:
基本類型 | 類 |
---|---|
byte | Byte |
short | Short |
int | Integer |
long | Long |
float | Float |
double | Double |
char | Character |
boolean | Boolean |
除了后兩個Character和Boolean類是Object派生類外,其余六個是繼承自Number類。
這些類稱為包裝器(wrapper),一旦構造了對象包裝器,就不允許更改包裝器在其中的值同時,對象包裝器類還是final修飾,所以也不能定義繼承它們的子類。
有時候需要將基本類型轉換為對象,比如定義一個整數(shù)型列表,尖括號中的類型參數(shù)不允許是基本類型,即不允許寫成ArrayList<int>,這時就需要用到Integer包裝器類,可以聲明一個Integer對象的數(shù)組列表ArrayList<Integer>。
而且為了便于添加int類型的元素到ArrayList<Integer>中,下面語句會自動裝箱
list.add(8);
即自動地變換成:
list.add(Integer.valueof(8));
再比如Integer num=8;
也是自動裝箱,會轉換成Integer num=Integer.valueOf(8);,
即將基本類型賦值給相應的類時,會觸發(fā)自動裝箱。
但是由于裝箱操作會創(chuàng)建對象,頻繁的裝箱操作會消耗許多內(nèi)存,影響性能,所以應該盡量避免裝箱。
拆箱
同樣的,將類轉換為對應的基本類型的過程就稱為拆箱,如上面的Integer類型變量num,int num2=num;
就會觸發(fā)自動拆箱,自動地轉換為int num2=num.intValue();
。
還有在算術表達式中也能夠自動地裝箱和拆箱,例如:
Integer n=6; n++; n-=2;
編譯器將自動地插入一條對象拆箱的指令,然后進行自增計算,最后再將結果裝箱。
注意裝箱和拆箱是編譯器認可的,而不是虛擬機,編譯器在生成類的字節(jié)碼時,插入必要的方法調(diào)用,而虛擬機只是執(zhí)行這些字節(jié)碼。
使用數(shù)值對象包裝器可以將某些基本方法防止在包裝器中,例如parseInt()
方法將一個數(shù)字字符串轉換成數(shù)值,parseInt()
是一個靜態(tài)方法,與這里的Integer類對象沒有任何關系,只是Integer類是放置這個方法的一個好地方罷了。
而我們的拆箱裝箱無非是自動的調(diào)用了放置在類里面的方法如intValue()
和valueOf()
等。
==
首先看看Integer.valueOf()
函數(shù)的源碼,就知道==的坑了。
public static Integer valueOf(int i) { return i >= 128 || i < -128 ? new Integer(i) : SMALL_VALUES[i + 128]; }
它會首先判斷 i i i的大?。喝绻?i > = 128 ∣ ∣ i < − 128 i>=128||i<-128 i>=128∣∣i<−128,就創(chuàng)建一個Integer對象,否則執(zhí)行SMALL_VALUES[i + 128],再定位到SMALL_VALUES:
private static final Integer[] SMALL_VALUES = new Integer[256];
它是一個已經(jīng)創(chuàng)建好的靜態(tài)的Integer數(shù)組對象,也就是說 i i i在 [ − 128 , 128 ) [-128,128) [−128,128)的范圍內(nèi)時,不會創(chuàng)建新的對象,否則會創(chuàng)建新的對象,這也就是裝箱為什么創(chuàng)建對象,從而消耗內(nèi)存。
(
插播反爬信息)博主CSDN地址:https://wzlodq.blog.csdn.net/
比如以下==判斷:
public static void main(String[] args) { Integer i1=88; Integer i2=88; Integer i3=666; Integer i4=666; System.out.println(i1==i2);//true System.out.println(i3==i4);//false }
==是判斷兩個對象的內(nèi)存地址是不是相等,顯然88在區(qū)間(-128,128)內(nèi),直接指向同一個創(chuàng)建好的數(shù)組,而666則會重新創(chuàng)建新對象。
同樣的boolean、byte、char<128;shot、int介于[-128,127]間時,會包裝到固定的對象中,比較結果一定成立,否則會創(chuàng)建新的對象,比較結果不成立。
這樣我們就能知道,混用時是自動拆箱還是自動裝箱了,如:
Integer n=666; int m=666; System.out.println(n==m);//true
如果是n自動拆箱,則指向常量池同一地址,則結果為true;如果是m自動裝箱,不在區(qū)間范圍內(nèi),創(chuàng)建新對象,則結果為false。答案是n自動拆箱。
再如:
Integer x=100; int y=200; Long z=300l; System.out.println(x+y==z);//true System.out.println(z.equals(x+y));//false
如果x、y、z自動拆箱則指向常量池同一地址,==結果true;如果x、y拆箱后裝箱成Long,不在區(qū)間范圍內(nèi),創(chuàng)建新對象,= =結果是false。答案是會拆箱。
那equals為什么輸出false?因為equals除了比較值相同外,還會比較數(shù)據(jù)類型,顯然兩者拆箱后分別是int和long型,故判斷為false。
null
由于包裝類的引用可以為null,所以自動裝箱時可能會拋出一個NullPointerException
異常,如:
Integer n=null; int m=n;
另外如果在一個條件表達式中混合使用Integer和Double類型,Integer值會拆箱,提升為Double,再裝箱為Double:
Integer n=6; Double m=8.0; System.out.println(true?n:m); //6.0
總結
本篇文章就到這里了,希望能給你帶來幫助,也希望您能夠多多關注腳本之家的更多內(nèi)容!
相關文章
解決在for循環(huán)中remove list報錯越界的問題
這篇文章主要介紹了解決在for循環(huán)中remove list報錯越界的問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-12-12