Java进阶之自动拆箱与自动装箱
序. java基本類型介紹
java中,基本數(shù)據(jù)類型一共有8種,詳細(xì)信息如下表:
| 類型 | 大小 | 范圍 | 默認(rèn)值 |
| 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語言是一種面向?qū)ο蟮恼Z言,但是Java中的基本數(shù)據(jù)類型卻是不面向?qū)ο蟮?#xff0c;這在實(shí)際使用時(shí)存在很多的不便,為了解決這個(gè)不足,設(shè)計(jì)者將每個(gè)基本數(shù)據(jù)類型單獨(dú)封裝成一個(gè)類,這八個(gè)和基本數(shù)據(jù)類型對(duì)應(yīng)的類統(tǒng)稱為包裝類(Wrapper Class)。
1.什么是自動(dòng)拆箱與自動(dòng)裝箱
自動(dòng)裝箱:把基本類型用它們對(duì)應(yīng)的包裝類包裝起來,使它們具有對(duì)象的特質(zhì),可以調(diào)用所對(duì)應(yīng)的包裝類所定義的方法,比如toString()等。
舉個(gè)例子:
Integer i0 = new Integer(0);Integer i1 = 2; Integer i1_ = Integer.valueOf(2); ?
上面的三行代碼第一行是最基本的創(chuàng)建一個(gè)integer對(duì)象的方式。第二行代碼就是我們這里要講的自動(dòng)裝箱。而第三行代碼就是第二行代碼的本質(zhì),也 就是說,當(dāng)你使用自動(dòng)裝箱來得到一個(gè)引用數(shù)據(jù)類型時(shí),jvm實(shí)際上調(diào)用了valueOf()方法,稍后我們會(huì)去研究一下java源碼。
自動(dòng)拆箱:跟自動(dòng)裝箱的方向相反,將Integer及Double這樣的包裝類的對(duì)象重新簡(jiǎn)化為基本類型的數(shù)據(jù)。
舉個(gè)例子:
1.System.out.println(i1+2); - 1
這句代碼就使用了自動(dòng)拆箱。i1是我們上面通過自動(dòng)裝箱得到的一個(gè)integer對(duì)象,而這個(gè)對(duì)象是不能直接進(jìn)行四則運(yùn)算的,但是我們卻給它+2,這樣就必須將integer對(duì)象轉(zhuǎn)變?yōu)榛緮?shù)據(jù)類型(int),這個(gè)過程就是自動(dòng)拆箱的過程。
p.s.所謂自動(dòng),就是說這個(gè)過程并不需要程序員去完成,而是jvm自動(dòng)完成的,jvm會(huì)在編譯期根據(jù)語法決定是否進(jìn)行裝箱和拆箱動(dòng)作。
另外,自動(dòng)拆箱與自動(dòng)裝箱的jdk1.5才引入的新特性,所以如果你的jdk版本低于1.5的話,是不可以這樣寫的。
2.為什么會(huì)有自動(dòng)拆箱與自動(dòng)裝箱
為什么java要提供這樣一個(gè)功能呢?我的理解是這樣的:
1.因?yàn)閼小<偃鐩]有自動(dòng)拆箱與自動(dòng)裝箱,那么我們的代碼是這樣的:
Integer i = new Integer(2);//假如需要一個(gè)integer的對(duì)象i,值為2 int b=i.intValue();//又需要一個(gè)int型的值,大小與i相等 ?
但是,有了自動(dòng)拆箱與裝箱,我們就可以這么寫:
Integer i = 2;int b = i; ?
是不是省了不少事,而且看起來代碼更簡(jiǎn)潔了呢?
2.自動(dòng)裝箱的過程其實(shí)可以起到節(jié)約內(nèi)存的作用。我們先看一個(gè)例子:
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呢?這是因?yàn)?#xff0c;在自動(dòng)裝箱時(shí)對(duì)于值從–128到127之間的值,它們被裝箱為 Integer對(duì)象后,會(huì)存在內(nèi)存中被重用,始終只存在一個(gè)對(duì)象 。而如果超過了從–128到127之間的值,被裝箱后的Integer對(duì)象并不會(huì)被重用,即相當(dāng)于每次裝箱時(shí)都新建一個(gè) Integer對(duì)象。
那么,為什么要這么設(shè)計(jì)呢?一般來說,小數(shù)字的使用頻率很高,將小數(shù)字保存起來,讓其始終僅有一個(gè)對(duì)象可以節(jié)約內(nèi)存,提高效率。
這其實(shí)用到了一種叫做享元模式的設(shè)計(jì)模式,感興趣的可以去研究一下這個(gè)設(shè)計(jì)模式。
3.怎么使用自動(dòng)拆箱與自動(dòng)裝箱
使用方式通過上面的例子大家應(yīng)該也都清楚了,自動(dòng)拆箱與裝箱實(shí)際上就是jvm幫我們?nèi)フ{(diào)用一些函數(shù),這樣可以使我們省不少事,代碼也會(huì)看起來更簡(jiǎn)潔一些,不過在這里還有一點(diǎn)需要強(qiáng)調(diào),先看代碼:
Integer a = null;
int b = a; - 1
- 2
這么寫完全是符合java語法規(guī)范的,編譯也可以正常通過,但是很明顯,運(yùn)行的時(shí)候回拋出空指針異常。所以在這里提醒大家,在使用自動(dòng)拆箱時(shí),一定要確保包裝類的引用不為空。
4.源碼剖析
上面提到了幾個(gè)包裝類的方法,我們一Integer類為例,來看一看java源碼是什么樣子的。首先是valueOf()方法:
public static Integer valueOf(int i) {if (i >= IntegerCache.low && i <= IntegerCache.high) // 沒有設(shè)置的話,IngegerCache.high 默認(rèn)是127 return IntegerCache.cache[i + (-IntegerCache.low)]; return new Integer(i); } ?
上面講到,在自動(dòng)裝箱時(shí)對(duì)于值從–128到127之間的值,它們被裝箱為Integer對(duì)象后,會(huì)存在內(nèi)存中被重用。現(xiàn)在明白是為什么了吧,在調(diào)用 valueOf()方法的時(shí)候,會(huì)判斷你所給的數(shù)是不是在IntegerCache.low 和 i <= IntegerCache.high之間,如果是,那么他就在內(nèi)存中生成唯一的對(duì)象,當(dāng)你第二次想要生成它的時(shí)候,他會(huì)把第一次所生成對(duì)象的地址給你,不 會(huì)重新生成。而不在這個(gè)范圍里的數(shù),你每次所生成的對(duì)象都是不同的。
自動(dòng)裝箱池的大小是怎么定義的呢,Integer.java中有這樣一個(gè)內(nèi)部類
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類(這個(gè)是jdk1.8的源碼)定義了Integer自動(dòng)裝箱池的大小。從源碼中我們可以看到,下界是寫死的,就是 -128,但是上界卻是由參數(shù)integerCacheHighPropValue解碼得來的,這就表明,其實(shí)我們可以通過改變 integerCacheHighPropValue值的大小來自定義自動(dòng)裝箱池的大小,當(dāng)然,一般沒人會(huì)去改它。
Integer自動(dòng)裝箱池的范圍是-128~127
Byte,Short,Long范圍是-128~127
Character范圍是0~127
Float和Double沒有自動(dòng)裝箱池
5.總結(jié)
Java通過自動(dòng)裝箱和拆箱的機(jī)制,節(jié)省了部分內(nèi)存開銷和創(chuàng)建對(duì)象的開銷,提高了效率同時(shí)簡(jiǎn)化了代碼。在使用該機(jī)制的時(shí)候,需要注意以下幾點(diǎn):
1.在進(jìn)行==比較的時(shí)候,在自動(dòng)裝箱池范圍內(nèi)的數(shù)據(jù)的引用是相同的,范圍外的是不同的。
2。在自動(dòng)拆箱時(shí),要保證包裝類的引用不為空。
參考:
http://blog.csdn.net/qq_31655965/article/details/51597285
轉(zhuǎn)載于:https://www.cnblogs.com/AndyAo/p/8134319.html
總結(jié)
以上是生活随笔為你收集整理的Java进阶之自动拆箱与自动装箱的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。