基本數據類型的自動裝箱(autoboxing)、拆箱(unboxing)是自J2SE 5.0開始提供的功能。
一般我們要創建一個類的對象實例的時候,我們會這樣:
Class a = new Class(parameter);
當我們創建一個Integer對象時,卻可以這樣:
Integer i = 100; (注意:不是 int i = 100; )
實際上,執行上面那句代碼的時候,系統為我們執行了:Integer i = Integer.valueOf(100);
此即基本數據類型的自動裝箱功能。
基本數據類型不是對象,也就是使用int、double、boolean等定義的變量、常量。
基本數據類型沒有可調用的方法。
eg: int t = 1; t. 后面是沒有方法滴。
Integer t =1; t. 后面就有很多方法可讓你調用了。
例如:Integer i = 100;
相當于編譯器自動為您作以下的語法編譯:Integer i = Integer.valueOf(100);
自動拆箱(unboxing),也就是將對象中的基本數據從對象中自動取出。如下可實現自動拆箱:
Integer i = 10; //裝箱 int t = i; //拆箱,實際上執行了 int t = i.intValue();在進行運算時,也可以進行拆箱。
Integer i = 10; System.out.PRintln(i++);輸出的結果是:
i1==i2: false i3==i4: true說明:
equals() 比較的是兩個對象的值(內容)是否相同。
“==” 比較的是兩個對象的引用(內存地址)是否相同,也用來比較兩個基本數據類型的變量值是否相等。
前面說過,int 的自動裝箱,是系統執行了 Integer.valueOf(int i),先看看Integer.java的源碼:
public static Integer valueOf(int i) { if(i >= -128 && i <= IntegerCache.high) // 沒有設置的話,IngegerCache.high 默認是127 return IntegerCache.cache[i + 128]; else return new Integer(i);}對于–128到127(默認是127)之間的值,Integer.valueOf(int i) 返回的是緩存的Integer對象(并不是新建對象)
所以范例中,i3 與 i4實際上是指向同一個對象。
而其他值,執行Integer.valueOf(int i) 返回的是一個新建的 Integer對象,所以范例中,i1與i2 指向的是不同的對象。
當然,當不使用自動裝箱功能的時候,情況與普通類對象一樣,請看下例:
Integer i3 =new Integer(100); Integer i4 =new Integer(100); System.out.println("i3==i4: "+(i3==i4));//顯示false先看個例子:
1 String str1 ="abc";2 String str2 ="abc";3 System.out.println(str2==str1); //輸出為 true 4 System.out.println(str2.equals(str1)); //輸出為 true 5 6 String str3 =new String("abc");7 String str4 =new String("abc"); 8 System.out.println(str3==str4); //輸出為 false 9 System.out.println(str3.equals(str4)); //輸出為 true這個怎么解釋呢?貌似看不出什么。那再看個例子。
String d ="2"; String e ="23"; e = e.substring(0, 1); System.out.println(e.equals(d)); //輸出為 true System.out.println(e==d); //輸出為 false第二個例子中,e的初始值與d并不同,因此e與d是各自創建了個對象,(e==d)為false 。 同理可知,第一個例子中的str3與str4也是各自new了個對象,而str1與str2卻是引用了同一個對象。
原帖(http://www.cnblogs.com/danne823/archive/2011/04/22/2025332.html)
因為在學習集合時知道集合里存放的對象都是Object類型,取出的時候需要強制類型轉換為目標類型(使用泛型集合不需要),如int a = (Integer)arrayList.get(0);然后我們就會發現,為什么要強制轉換為Integer,而不是int呢?int與Integer有什么區別呢?
int是基本類型,直接存數值;如:
int i = 5;//直接在棧中分配空間,存放5這個數值Integer是int的包裝類,是類,擁有方法;如:
Integer i = new Integer(5); //i是對象的引用變量,所以在堆內存中分配對象空間,棧中存放堆內存中對應空間的地址Java有八種基本數據類型,對應八種包裝類: short Short int Integer long Long char Character byte Byte float Float boolean Boolean double Double
變量的值存儲在棧里,而對象存儲在堆里,相比而言,堆棧更高效,這也是java保留基本類型的原因。包裝類創建的對象,可以使用api提供的一些有用的方法。更為強大。
那我們來分析Integer i = 5;的過程; 在jdk1.5以前,這樣的代碼是錯誤的,必須要通過Integer i = new Integer(5);這樣的語句實現;而在jdk1.5以后,Java提供了自動裝箱的功能,只需Integer i = 5;這樣的語句就能實現基本數據類型傳給其包裝類,JVM為我們執行了Integer i = Integer.valueOf(5);這就是Java的自動裝箱。 相對應的,把基本數據從對應包裝類中取出的過程就是拆箱;如 Integer i = 5; int j = i;//這樣的過程就是自動拆箱
源碼方面,用一句話總結裝箱和拆箱的實現過程: 裝箱過程是通過調用包裝器的valueOf方法實現的,而拆箱過程是通過調用包裝器的 xxxValue方法實現的。(xxx代表對應的基本數據類型) Integer i = new Integer(xxx)和Integer i =xxx;這兩種方式的區別: 1)第一種方式不會觸發自動裝箱的過程;而第二種方式會觸發; 2)在執行效率和資源占用上的區別。第二種方式的執行效率和資源占用在一般性情況下要優于第一種情況(注意這并不是絕對的)。
a、這里就有一個面試經常會出現的問題,看下面這段代碼:
public class Main { public static void main(String[] args) { Boolean i1 = false; Boolean i2 = false; Boolean i3 = true; Boolean i4 = true; System.out.println(i1==i2); System.out.println(i3==i4); } }輸出結果是什么呢? true false 出現這樣結果的原因可由源碼解釋:
public static Integer valueOf(int i) { if(i >= -128 && i <= IntegerCache.high) // 沒有設置的話,IngegerCache.high 默認是127 return IntegerCache.cache[i + 128]; else return new Integer(i); }而其中IntegerCache類的實現為:
private static class IntegerCache { static final int high; static final Integer cache[]; static { final int low = -128; // high value may be configured by property int h = 127; if (integerCacheHighPropValue != null) { // Use Long.decode here to avoid invoking methods that // require Integer's autoboxing cache to be initialized int i = Long.decode(integerCacheHighPropValue).intValue(); i = Math.max(i, 127); // Maximum array size is Integer.MAX_VALUE h = Math.min(i, Integer.MAX_VALUE - -low); } high = h; cache = new Integer[(high - low) + 1]; int j = low; for(int k = 0; k < cache.length; k++) cache[k] = new Integer(j++); } private IntegerCache() {} }從這2段代碼可以看出,在通過valueOf方法創建Integer對象的時候,如果數值在[-128,127]之間,便返回指向IntegerCache.cache中已經存在的對象的引用;否則創建一個新的Integer對象。 上面的代碼中i1和i2的數值為100,因此會直接從cache中取已經存在的對象,所以i1和i2指向的是同一個對象,而i3和i4則是分別指向不同的對象。
b、而如果把上一道題中的四個數據類型換做Double或Float,那么結果是什么?
public static void main(String[] args) { Double i1 = 100.0; Double i2 = 100.0; Double i3 = 200.0; Double i4 = 200.0; System.out.println(i1==i2); System.out.println(i3==i4); } }答案是都為false!至于具體為什么,讀者可以去查看Double類的valueOf的實現。 在這里只解釋一下為什么Double類的valueOf方法會采用與Integer類的valueOf方法不同的實現。很簡單:在某個范圍內的整型數值的個數是有限的,而浮點數卻不是。 注意,Integer、Short、Byte、Character、Long這幾個類的valueOf方法的實現是類似的。Double、Float的valueOf方法的實現是類似的。
c、換做Boolean呢?
public class Main { public static void main(String[] args) { Boolean i1 = false; Boolean i2 = false; Boolean i3 = true; Boolean i4 = true; System.out.println(i1==i2); System.out.println(i3==i4); } }答案是都為true! 至于為什么是這個結果,看了Boolean類的源碼也會一目了然。下面是Boolean的valueOf方法的具體實現:
public static Boolean valueOf(boolean b) { return (b ? TRUE : FALSE); }而其中的 TRUE 和FALSE又是什么呢?在Boolean中定義了2個靜態成員屬性:
public static final Boolean TRUE = new Boolean(true); /** * The <code>Boolean</code> object corresponding to the primitive * value <code>false</code>. */ public static final Boolean FALSE = new Boolean(false);至此,大家應該明白了為何上面輸出的結果都是true了。
d、下面這段代碼輸出什么?
public class Main { 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)); } }先別看輸出結果,讀者自己想一下這段代碼的輸出結果是什么。這里面需要注意的是:當 “==”運算符的兩個操作數都是 包裝器類型的引用,則是比較指向的是否是同一個對象,而如果其中有一個操作數是表達式(即包含算術運算)則比較的是數值(即會觸發自動拆箱的過程)。另外,對于包裝器類型,equals方法并不會進行類型轉換。明白了這2點之后,上面的輸出結果便一目了然: true false true true true false true 第一個和第二個輸出結果沒有什么疑問。第三句由于 a+b包含了算術運算,因此會觸發自動拆箱過程(會調用intValue方法),因此它們比較的是數值是否相等。而對于c.equals(a+b)會先觸發自動拆箱過程,再觸發自動裝箱過程,也就是說a+b,會先各自調用intValue方法,得到了加法運算后的數值之后,便調用Integer.valueOf方法,再進行equals比較。同理對于后面的也是這樣,不過要注意倒數第二個和最后一個輸出的結果(如果數值是int類型的,裝箱過程調用的是Integer.valueOf;如果是long類型的,裝箱調用的Long.valueOf方法)。
原帖(http://blog.csdn.net/zhangliangzi/article/details/50552587)
新聞熱點
疑難解答