1. 程式人生 > >Java 裝箱 拆箱

Java 裝箱 拆箱

內部 其中 rac htm integer 重寫 什麽 這樣的 自動調用

以前都沒有聽說過,這次看海子的博客,真是長見識了!

https://www.cnblogs.com/dolphin0520/p/3780005.html

簡單一點說,裝箱就是自動將基本數據類型轉換為包裝器類型;拆箱就是自動將包裝器類型轉換為基本數據類型。

1         //自動裝箱
2         Integer num = 3;
3         //自動拆箱
4         int count = num;

在裝箱的時候自動調用的是Integer的valueOf(int)方法。而在拆箱的時候自動調用的是Integer的intValue方法。

因此可以用一句話總結裝箱和拆箱的實現過程:

裝箱過程是通過調用包裝器的valueOf方法實現的,而拆箱過程是通過調用包裝器的 xxxValue方法實現的。(xxx代表對應的基本數據類型)。

下面這段代碼是Integer的valueOf方法的具體實現:

public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}

在通過valueOf方法創建Integer對象的時候,如果數值在[-128,127]之間,便返回指向IntegerCache.cache中已經存在的對象的引用;否則創建一個新的Integer對象。

IntegerCache.cache[]是一個靜態的Integer數組對象,也就是說最終valueOf返回的都是一個Integer對象。

上面我們看到在Integer的構造函數中,它分兩種情況:

1、i >= 128 || i < -128 =====> new Integer(i)
2、i < 128 && i >= -128 =====> SMALL_VALUES[i + 128]

1 static final Integer cache[] = new Integer[256];

cache本來已經被創建好,也就是說在i >= 128 || i < -128是會創建不同的對象,在i < 128 && i >= -128會根據i的值返回已經創建好的指定的對象。

下面是幾個例子:

 1 package lesson1213;
 2 
 3 public class TestZhuangXiang {
 4 
 5     public static void main(String[] args) {
 6         //自動裝箱
 7         Integer num1 = 3;        
 8         Integer num2 = 3;
 9         
10         Integer num3 = 200;
11         Integer num4 = 200;
12         
13         System.out.println(num1==num2);  //true
14         System.out.println(num3==num4);  //false
15         
16     }
17 
18 }

如果是Double類呢?

1         Double d1 = 1.0;
2         Double d2 = 1.0;
3         Double d3 = 200.0;
4         Double d4 = 200.0;
5         
6         System.out.println(d1==d2);  //false
7         System.out.println(d3==d4);  //false

看看上面的執行結果,跟Integer不一樣,這樣也不必奇怪,因為它們的valueOf實現不一樣,結果肯定不一樣,那為什麽它們不統一一下呢?
這個很好理解,因為對於Integer,在(-128,128]之間只有固定的256個值,所以為了避免多次創建對象,我們事先就創建好一個大小為256的Integer數組SMALL_VALUES,所以如果值在這個範圍內,就可以直接返回我們事先創建好的對象就可以了。

但是對於Double類型來說,我們就不能這樣做,因為它在這個範圍內個數是無限的。
總結一句就是:在某個範圍內的整型數值的個數是有限的,而浮點數卻不是。

所以在Double裏面的做法很直接,就是直接創建一個對象,所以每次創建的對象都不一樣。

1     public static Double valueOf(double d) {
2         return new Double(d);
3     }

下面我們進行一個歸類:
Integer派別:Integer、Short、Byte、Character、Long這幾個類的valueOf方法的實現是類似的。
Double派別:Double、Float的valueOf方法的實現是類似的。每次都返回不同的對象。

下面對Integer派別進行一個總結,如下圖:
技術分享圖片

下面我們來看看另外一種情況:Boolean類

1         Boolean b1 = true;
2         Boolean b2 = true;
3         Boolean b3 = false;
4         Boolean b4 = false;
5         System.out.println(b1==b2); //true
6         System.out.println(b3==b4); //true

可以看到返回的都是true,也就是它們執行valueOf返回的都是相同的對象。

1     public static Boolean valueOf(boolean b) {
2         return (b ? TRUE : FALSE);
3     }

可以看到並沒有創建對象,因為已經在內部提前創建好了兩個對象,因為只有兩種情況,這樣也是為了避免重復創建太多對象。

1     public static final Boolean TRUE = new Boolean(true);
2     public static final Boolean FALSE = new Boolean(false);

下面講述下equal 和 == 在這幾個類中的應用

 1 package lesson1213;
 2 
 3 public class Test {
 4     
 5     /*1:== 比較兩個值是否相等。如果作用於基本數據類型,比較其值是否相等。
 6          * 如果作用於引用類型變量,則比較的是所指向對象的地址。
 7       2:在object中equal,equal方法是用來比較兩個對象的引用是否相等,即是否指向同一個對象。
 8       但是有一些類例如String,Double, Date,Interger等,都對equal方法進行了重寫用來比較應用的對象所存儲的值是否相等。
 9       註意equal不能用於基本數據類型。
10     */    
11     
12     public static void main(String[] args) {
13         Integer num1 = 200;
14         int num2 = 200;
15         System.out.println(num1==num2);         //true
16         System.out.println(num2==num1);            //true    
17         System.out.println(num1.equals(num2));  //true
18         
19         Integer a = 1;
20         Integer b = 2;
21         Integer c = 3;
22         Integer d = 3;
23         Integer e = 300;
24         Integer f = 300;
25         Long g = 3L;
26         Long h = 2L;
27         
28         Integer e1 = 100;
29         Integer e2 = 200;
30         int e3=100;
31         int e4=200;
32         
33         System.out.println(c==d);              //true,  沒有疑問
34         System.out.println(e==f);              //false, 超過範圍-128~127,每次都重新new
35         System.out.println(e==f+0);            //true, 如果有操作運算符,就是比較的值
36         System.out.println(c==(a+b));          //true
37         System.out.println(c.equals((a+b)));   //true
38         System.out.println(g==(a+b));          //true   //有操作運算符
39         System.out.println(g.equals((a+b)));   //false  //類型不一樣
40         System.out.println(g.equals((a+h)));   //true   //自動提升類型
41         System.out.println(g==(a+h));          //true    
42         System.out.println(e==(e1+e2));        //true
43         System.out.println(e.equals((e1+e2))); //true
44         System.out.println(e==(e1+e4));        //true
45         System.out.println(e.equals((e2+e3))); //true
46     }
47 }

總結:

1:當 "=="運算符的兩個操作數都是 包裝器類型的引用,則是比較指向的是否是同一個對象,而如果其中有一個操作數是表達式(即包含算術運算)則比較的是數值(即會觸發自動 拆箱的過程)。

補充:"=="只有兩個都是包裝類型,並且沒有操作運算,才是比較是否指向同一個對象。如果有一個是包裝類型,另一個不是包裝類型,則比較的就是值。

當兩種不同類型用==比較時,包裝器類的需要拆箱, 當同種類型用==比較時,會自動拆箱或者裝箱

當一個基礎數據類型與封裝類進行==、+、-、*、/運算時,會將封裝類進行拆箱,對基礎數據類型進行運算。

2:equal, 首先判斷類型是否一樣,如果一樣,就看值是否相等。對於包裝器類型,equals方法並不會進行類型轉換。

下面是Integer中對equal進行重載:

1     public boolean equals(Object obj) {
2         if (obj instanceof Integer) {
3             return value == ((Integer)obj).intValue();
4         }
5         return false;
6     }

line36由於 a+b包含了算術運算,因此會觸發自動拆箱過程(會調用intValue方法),因此它們比較的是數值是否相等。

line37對於c.equals(a+b)會先觸發自動拆箱過程,再觸發自動裝箱過程,也就是說a+b,會先各自調用intValue方法,得到了加法運算後的數值之後,便調用Integer.valueOf方法,再進行equals比較。

下面這個例子有點奇怪,自己也不是很了解,但是程序運行結果就是這樣:會自動提升類型,所以相等

 1         int e5 = 3;
 2         long e6 = 3;        
 3         //Long e66 = 3;                        //編譯失敗Type mismatch: cannot convert from int to Long
 4         Long e666=3L; 
 5         Double e7 = 3.0;
 6         Integer e8 = 3;
 7         
 8         System.out.println(e5==e6);            //true
 9         System.out.println(e5==e666);          //true
10         System.out.println(e5==e7);            //true
11         System.out.println(e6==e7);            //true, 一邊是基礎類型,一般是包裝類,比較值
12         System.out.println(e6==e8);            //true
13         //System.out.println(e7==e8);          //編譯失敗Incompatible operand types Double and Integer

到此處,應該對包裝類和裝箱,拆箱比較了解了,在遇見這樣的題目應該沒有問題了。

Java 裝箱 拆箱