Java學習筆記 (十五) 自動拆箱與自動裝箱
什麼是自動拆裝箱
- 自動裝箱: 就是將基本資料型別自動轉換成對應的包裝類.
- 自動拆箱:就是將包裝類自動轉換成對應的基本資料型別。
For example :
Integer a=1; //自動裝箱
int b=a; //自動拆箱
基本資料型別與包裝類對應關係,如下:
基本資料型別 | 包裝類 |
---|---|
boolean | Boolean |
byte | Byte |
char | Character |
float | Float |
int | Integer |
long | Long |
short | Short |
double | Double |
自動拆裝箱是怎麼實現的
我們可以通過反編譯去看他是如何實現的,反編譯前程式碼:
public static void main(String[]args){
Integer integer=1; //裝箱
int i=integer; //拆箱
Double dou=2.0; //裝箱
double dou2=dou; //拆箱
Float f=3f;//裝箱
float f2=f;//拆箱
Byte b=4;//裝箱
byte b2=b;//拆箱
Long lo=5l;//裝箱
long lo2=lo;//拆箱
Character character=6;//裝箱
char c2=character;//拆箱
Boolean bl=false;//裝箱
boolean bl2=bl;//拆箱
Short s=8;//裝箱
short s2=s;//拆箱
}
反編譯後代碼:
從上面反編譯後的程式碼可以看出,自動裝箱都是通過包裝類的valueOf()方法來實現的.自動拆箱都是通過包裝類物件的**Value()來實現的。
包裝類比較資料大小是自動拆箱進行比較的嗎
原始碼:
Integer a=1;
System.out.println(a==1?"等於":"不等於");
Boolean bool=false;
System.out.println(bool?"真":"假");
反編譯後:
可以看到,包裝類進行比較運算,是先進行拆箱成基本資料型別,然後進行運算的。
自動拆裝箱有什麼用
我從官網偷了個例子:
List<Integer> li = new ArrayList<>();
for (int i = 1; i < 50; i += 2)
li.add(i);
為什麼上面的程式碼不報錯呢,因為編譯時程式碼自動轉換了一下,如下:
List<Integer> li = new ArrayList<>();
for (int i = 1; i < 50; i += 2)
li.add(Integer.valueOf(i));
所以 li集合裡面存的實際上是Interger物件,而不是基礎資料型別。
- 第一,方便使用,包裝類中有很多方法,比如轉換成其他資料型別的方法,等等
- 第二, 多型,我們都知道,所有的類都繼承了Object ,而基本資料型別沒有繼承,所有使用包裝類可以使用多型這個特性,就像上面那個例子。
自動拆裝的疑惑?
一、包裝類物件為什麼會相等
看,a==b 為true,c==d 為false
Integer a=2;
Integer b=2;
Integer c=128;
Integer d=128;
System.out.println(a==b); //true
System.out.println(c==d); //false
運算元都是物件,“==” 比較的是引用地址,都是自動裝箱。應該都是false才是,為什麼是a==b是true呢?
我們知道,自動裝箱是通過valueOf()方法來實現的,原始碼如下:
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
可以看出來,數值大小在low到high之間返回的是快取中的物件,超出這個範圍則是new 一個返回。low= -128 ;high如果不指定的話值為127;
很顯然,2在這個範圍,所以Integer.valueOf(2)的時候,返回的是快取的物件,所以a和b其實是一個物件所以相等。
其他幾個包裝類中;Double與Float是直接new 一個物件返回的;Long,Short,Character與Integer類似,而Byte則是直接返回快取中的物件,想一下Byte的取值範圍就明白了;Boolean比較特殊,一共就兩個值,如下:
二、什麼時候會進行自動拆裝箱
看一段我從某位大佬那裡借鑑(偷)過來的程式碼:
Integer a = 1;
Integer b = 2;
Integer c = 3;
Long g = 3L;
Long h = 2L;
System.out.println(c==(a+b)); //1. true
System.out.println(g==(a+b)); //2. true
System.out.println(c.equals(a+b));//3. true
System.out.println(g.equals(a+b)); //4. false
System.out.println(g.equals(a+h));//5. true
仔細想下,為什麼會這樣呢?我來分析下,如果您認為我分析有誤或者有疑問歡迎聯絡我。
- 1、為什麼c==(a+b) 為true?
是因為,a+b 是進行算術運算,上文提到過,算術運算時,會拆箱成基本資料型別進行運算,那麼a+b的結果也是基本資料型別,而包裝類型別進行==比較時,如果有一方是基本資料型別,那麼包裝類型別會進行拆箱。所以c==(a+b) 比較的是數值是否相等。 結果為true - 2、為什麼g==(a+b) 為true?
同1。 - 3、c.equals(a+b) 為什麼為 true?
首先放一段Integer.eqquals()的原始碼:
public boolean equals(Object obj) {
if (obj instanceof Integer) {
return value == ((Integer)obj).intValue();
}
return false;
}
看了上面的原始碼就很好理解了,a和b都是Integer型別,拆箱算術運算結束後結果也是int 型別,然後equals需要的是物件,所以這裡會進行裝箱,還是Integer型別,然後型別判斷結果為true,比較的是數值,所以結果為true。
- 4、g.equals(a+b) 為什麼是false呢?
g是Long型別,我們看下Long的equals()方法;
public boolean equals(Object obj) {
if (obj instanceof Long) {
return value == ((Long)obj).longValue();
}
return false;
}
看了原始碼很容易就知道為什麼了,上面說過a+b結果為int型別,在這裡自動裝箱也是對應的Integer型別,Integer 型別不屬於Long型別,結果為false,直接返回false,
- 5、g.equals(a+h)為什麼為true?
相信你已經很明白了為什麼了。
下面放出反編譯後的程式碼,很容易就看出哪裡進行了拆箱裝箱。