java自動裝箱拆箱特性
http://www.cnblogs.com/dolphin0520/p/3780005.html
在Java SE5 之前,如果要生成一個數值為10的Integer物件,必須這樣進行:
Integer i = new Integer(10);
而在 從Java SE5開始 就提供了 自動裝箱 的特性,如果要生成一個數值為10的Integer物件,只需要這樣就可以了:
Integer i = 10;
這個過程中會自動根據數值建立對應的 Integer物件,這就是裝箱。
Integer i = 10; //裝箱
int n = i; //拆箱
簡單一點說:
裝箱就是 自動將基本資料型別轉換為包裝器型別;
拆箱就是 自動將包裝器型別轉換為基本資料型別。
在裝箱的時候自動呼叫的是 Integer的 valueOf( ) 方法
在拆箱的時候自動呼叫的是 Integer的 intValue( ) 方法
最關鍵的下面的面試問題:
public class Main { public static void main(String[] args) { Integer i1 = 100; Integer i2 = 100; Integer i3 = 200; Integer i4 = 200; System.out.println(i1==i2); System.out.println(i3==i4); } } 控制檯結果: true false
為什麼是這個結果呢
看一哈 Integer 的 valueOf( ) 方法的具體實現:
public static Integer valueOf(int i) { if( i >= -128 && i <= IntegerCache.high ) /* 如果傳入的 int 在 [-128,127] 之間,便返回 指向IntegerCache.cache中已經存在的物件的引用 */ return IntegerCache.cache[i + 128]; else // 否則建立一個新的Integer物件 return new Integer(i); }
我對這個 自動裝箱 過程的理解是 :
在 java 5 之後 ,java的開發者已經 默認準備了 [-128,127] 之間的128*2個 Integer 物件了,
這128*2個物件就像常量一樣被呼叫。
如果傳入的數字在此範圍內( 比如 i1、i2 ),則返回的都是人家提前備好的128*2個物件的引用
超出此範圍的話才會去建立新的物件並返回新物件的引用( 比如 i3、i4 ),
而每個新物件的引用又都是不一樣的,才導致了以上結果。
擴充套件:
Integer、Short、Byte、Character、Long這幾個類的valueOf方法的實現是類似的
Double、Float的valueOf方法的實現是類似的
Double類的 valueOf( ) 方法會採用與 Integer 類的 valueOf( ) 方法不同的實現。
原因:在某個範圍內的整型數值的個數是有限的(128*2),而浮點數卻是無限的,沒有辦法提前準備
至於 Boolean包裝類 就更簡單了,總共只能有兩個值,直接就準備好兩個靜態final物件就好了:
public static final Boolean TRUE = new Boolean(true);
public static final Boolean FALSE = new Boolean(false);
public static Boolean valueOf(boolean b) {
return (b ? TRUE : FALSE);
}
練習:
(1) '=='比較的是a和b的地址,即比較a和b指向的是否是同一個物件
(2) 對於 ' Integer==int ' 類似的比較,即兩個運算元中有一個是(int) 的情況, 比較的是數值是否相等(即Integer型別的那個物件會觸發自動拆箱的過程)
public static void main(String[] args) {
Integer a = 1;
Integer b = 2;
Integer c = 3;
Integer d = 3;
Integer e = 321;
Integer f = 321;
Long g = 3L;
Long h = 2L;
System.out.println(c==d);
System.out.println(e==f);
System.out.println(c==(a+b));
System.out.println(c.equals(a+b));
System.out.println(g==(a+b));
System.out.println(g.equals(a+b));
System.out.println(g.equals(a+h));
}
1)c == d 為 true 不用多講,自動裝箱時用的是一個物件
2)e == f 為false 也不多說 , 自動裝箱時超出了範圍[ -128,127 ],e和f都是新建立的物件,兩個物件的地址自然不一樣
3)a+b 時會觸發自動拆箱操作(為什麼? a和b兩個都是物件不拆箱怎麼進行相加運算?當然要轉化成基本資料型別才能+),加完以後變成了 c == (int) ,根據以上(2),c會自動拆箱,即最後比較的是數值
4)c.equals(a+b) 會先觸發自動拆箱過程(a+b),再觸發自動裝箱過程(為什麼?相加的結果是作為引數傳入c.equals()方法中的,equals()要的當然是Object,當然要裝一波箱),也就是說a+b,會先各自呼叫各自的 intValue() 方法,得到了加法運算後的數值之後,便呼叫 Integer.valueOf() 方法,再和c進行equals比較
5)同3):用到了(2):a+b之後為int型,Long要觸發自動拆箱
6)a+b 的結果自動裝箱的時候呼叫的是Integer.valueOf() 方法,但 g 是用的Long裡提前存好的[ -128,127 ]內的物件,而 a+b 用 是Integer裡提前存好[ -127,128 ]的物件,連型別都不一樣,當然是不同的兩個物件
7)a和h 自動拆箱後,運算時 a會自動型別轉換成範圍更大的 long ,自動裝箱時呼叫的是 Long.valueOf() 方法
執行結果:
true
false
true
true
true
false
true
如果對上面的具體執行過程有疑問,可以嘗試獲取反編譯的位元組碼內容進行檢視:
https://blog.csdn.net/swq463/article/details/84678142
這是程式碼加反編譯的結果:
public static void main(String[] args) {
Integer b = 3; // Method java/lang/Integer.valueOf 自動裝箱
Long c = 3L; // Method java/lang/Long.valueOf 自動裝箱
System.out.println(c.equals(a)); // Method java/lang/Integer.valueOf a先自動裝箱
// Method java/lang/Long.equals
}