JavaStudy——Java之自動拆箱與自動裝箱


 java基本類型介紹

java中,基本數據類型一共有8種,詳細信息如下表:

類型 大小 范圍 默認值
byte 8 -128 - 127 0
short 16 -32768 - 32768 0
int 32 -2147483648-2147483648 0
long 64 -9233372036854477808-9233372036854477808 0
float 32 -3.40292347E+38-3.40292347E+38 0.0f
double 64 -1.79769313486231570E+308-1.79769313486231570E+308 0.0d
char 16 \u0000 - u\ffff \u0000
boolean 16 true/false false


Java語言是一種面向對象的語言,但是Java中的基本數據類型卻是不面向對象的,這在實際使用時存在很多的不便,為了解決這個不足,設計者將每個基本數據類型單獨封裝成一個類,這八個和基本數據類型對應的類統稱為包裝類(Wrapper Class)。

1.什么是自動拆箱與自動裝箱

自動裝箱:把基本類型用它們對應的包裝類包裝起來,使它們具有對象的特質,可以調用所對應的包裝類所定義的方法,比如toString()等。

舉個例子:

   Integer i0 = new Integer(0); Integer i1 = 2; Integer i1_ = Integer.valueOf(2);

 

上面的三行代碼第一行是最基本的創建一個integer對象的方式。第二行代碼就是我們這里要講的自動裝箱。而第三行代碼就是第二行代碼的本質,也就是說,當你使用自動裝箱來得到一個引用數據類型時,jvm實際上調用了valueOf()方法,稍后我們會去研究一下java源碼。

自動拆箱:跟自動裝箱的方向相反,將Integer及Double這樣的包裝類的對象重新簡化為基本類型的數據。

舉個例子:

        1.System.out.println(i1+2);

 

這句代碼就使用了自動拆箱。i1是我們上面通過自動裝箱得到的一個integer對象,而這個對象是不能直接進行四則運算的,但是我們卻給它+2,這樣就必須將integer對象轉變為基本數據類型(int),這個過程就是自動拆箱的過程。

p.s.所謂自動,就是說這個過程並不需要程序員去完成,而是jvm自動完成的,jvm會在編譯期根據語法決定是否進行裝箱和拆箱動作。 
另外,自動拆箱與自動裝箱的jdk1.5才引入的新特性,所以如果你的jdk版本低於1.5的話,是不可以這樣寫的。

2.為什么會有自動拆箱與自動裝箱

為什么java要提供這樣一個功能呢?我的理解是這樣的: 
1.因為懶。假如沒有自動拆箱與自動裝箱,那么我們的代碼是這樣的:

    Integer i = new Integer(2);//假如需要一個integer的對象i,值為2 int b=i.intValue();//又需要一個int型的值,大小與i相等
  • 1
  • 2

但是,有了自動拆箱與裝箱,我們就可以這么寫:

        Integer i = 2; int b = i;

 

是不是省了不少事,而且看起來代碼更簡潔了呢?

2.自動裝箱的過程其實可以起到節約內存的作用。我們先看一個例子:

        Integer a = 1; Integer b = 1; Integer c = 144; Integer d = 144; Integer a1 = new Integer(1); Integer b1 = new Integer(1); System.out.println(a == b); //true System.out.println(a.equals(b)); //true System.out.println(a1 == b1); //false System.out.println(a1.equals(b1)); //true System.out.println(c == d); //false System.out.println(c.equals(d)); //true

 

是不是很奇怪,為什么第7行為true而第12行為false呢?這是因為,在自動裝箱時對於值從–128到127之間的值,它們被裝箱為Integer對象后,會存在內存中被重用,始終只存在一個對象 。而如果超過了從–128到127之間的值,被裝箱后的Integer對象並不會被重用,即相當於每次裝箱時都新建一個 Integer對象。

那么,為什么要這么設計呢?一般來說,小數字的使用頻率很高,將小數字保存起來,讓其始終僅有一個對象可以節約內存,提高效率。

這其實用到了一種叫做享元模式的設計模式,感興趣的可以去研究一下這個設計模式。

3.怎么使用自動拆箱與自動裝箱

使用方式通過上面的例子大家應該也都清楚了,自動拆箱與裝箱實際上就是jvm幫我們去調用一些函數,這樣可以使我們省不少事,代碼也會看起來更簡潔一些,不過在這里還有一點需要強調,先看代碼:

Integer a = null; int b = a;

 

這么寫完全是符合java語法規范的,編譯也可以正常通過,但是很明顯,運行的時候回拋出空指針異常。所以在這里提醒大家,在使用自動拆箱時,一定要確保包裝類的引用不為空。

4.源碼剖析

上面提到了幾個包裝類的方法,我們一Integer類為例,來看一看java源碼是什么樣子的。首先是valueOf()方法:

public static Integer valueOf(int i) { if (i >= IntegerCache.low && i <= IntegerCache.high) // 沒有設置的話,IngegerCache.high 默認是127 return IntegerCache.cache[i + (-IntegerCache.low)]; return new Integer(i); }

 

上面講到,在自動裝箱時對於值從–128到127之間的值,它們被裝箱為Integer對象后,會存在內存中被重用。現在明白是為什么了吧,在調用valueOf()方法的時候,會判斷你所給的數是不是在IntegerCache.low 和 i <= IntegerCache.high之間,如果是,那么他就在內存中生成唯一的對象,當你第二次想要生成它的時候,他會把第一次所生成對象的地址給你,不會重新生成。而不在這個范圍里的數,你每次所生成的對象都是不同的。

自動裝箱池的大小是怎么定義的呢,Integer.java中有這樣一個內部類

private static class IntegerCache { static final int low = -128; static final int high; static final Integer cache[]; static { // high value may be configured by property int h = 127; String integerCacheHighPropValue = sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high"); if (integerCacheHighPropValue != null) { try { int i = parseInt(integerCacheHighPropValue); i = Math.max(i, 127); // Maximum array size is Integer.MAX_VALUE h = Math.min(i, Integer.MAX_VALUE - (-low) -1); } catch( NumberFormatException nfe) { // If the property cannot be parsed into an int, ignore it. } } high = h; cache = new Integer[(high - low) + 1]; int j = low; for(int k = 0; k < cache.length; k++) cache[k] = new Integer(j++); // range [-128, 127] must be interned (JLS7 5.1.7) assert IntegerCache.high >= 127; } private IntegerCache() {} }

 

IntegerCache類(這個是jdk1.8的源碼)定義了Integer自動裝箱池的大小。從源碼中我們可以看到,下界是寫死的,就是-128,但是上界卻是由參數integerCacheHighPropValue解碼得來的,這就表明,其實我們可以通過改變integerCacheHighPropValue值的大小來自定義自動裝箱池的大小,當然,一般沒人會去改它。

Integer自動裝箱池的范圍是-128~127 
Byte,Short,Long范圍是-128~127 
Character范圍是0~127 
Float和Double沒有自動裝箱池

5.總結

Java通過自動裝箱和拆箱的機制,節省了部分內存開銷和創建對象的開銷,提高了效率同時簡化了代碼。在使用該機制的時候,需要注意以下幾點: 
1.在進行==比較的時候,在自動裝箱池范圍內的數據的引用是相同的,范圍外的是不同的。 
2。在自動拆箱時,要保證包裝類的引用不為空。 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM