java中,基本數據類型一共有8種,詳細信息以下表:java
類型 | 大小 | 範圍 | 默認值 |
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)。程序員
自動裝箱:把基本類型用它們對應的包裝類包裝起來,使它們具備對象的特質,能夠調用所對應的包裝類所定義的方法,好比toString()等。設計模式
舉個例子:app
Integer i0 = new Integer(0); Integer i1 = 2; Integer i1_ = Integer.valueOf(2);
上面的三行代碼第一行是最基本的建立一個integer對象的方式。第二行代碼就是咱們這裏要講的自動裝箱。而第三行代碼就是第二行代碼的本質,也就是說,當你使用自動裝箱來獲得一個引用數據類型時,jvm實際上調用了valueOf()方法,稍後咱們會去研究一下java源碼。jvm
自動拆箱:跟自動裝箱的方向相反,將Integer及Double這樣的包裝類的對象從新簡化爲基本類型的數據。函數
舉個例子:spa
1.System.out.println(i1+2);
這句代碼就使用了自動拆箱。i1是咱們上面經過自動裝箱獲得的一個integer對象,而這個對象是不能直接進行四則運算的,可是咱們卻給它+2,這樣就必須將integer對象轉變爲基本數據類型(int),這個過程就是自動拆箱的過程。設計
p.s.所謂自動,就是說這個過程並不須要程序員去完成,而是jvm自動完成的,jvm會在編譯期根據語法決定是否進行裝箱和拆箱動做。
另外,自動拆箱與自動裝箱的jdk1.5才引入的新特性,因此若是你的jdk版本低於1.5的話,是不能夠這樣寫的。指針
爲何java要提供這樣一個功能呢?個人理解是這樣的:
1.由於懶。假如沒有自動拆箱與自動裝箱,那麼咱們的代碼是這樣的:code
Integer i = new Integer(2);//假如須要一個integer的對象i,值爲2 int b=i.intValue();//又須要一個int型的值,大小與i相等
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對象。
那麼,爲何要這麼設計呢?通常來講,小數字的使用頻率很高,將小數字保存起來,讓其始終僅有一個對象能夠節約內存,提升效率。
這其實用到了一種叫作享元模式的設計模式,感興趣的能夠去研究一下這個設計模式。
使用方式經過上面的例子你們應該也都清楚了,自動拆箱與裝箱實際上就是jvm幫咱們去調用一些函數,這樣可使咱們省很多事,代碼也會看起來更簡潔一些,不過在這裏還有一點須要強調,先看代碼:
Integer a = null; int b = a;
這麼寫徹底是符合java語法規範的,編譯也能夠正常經過,可是很明顯,運行的時候回拋出空指針異常。因此在這裏提醒你們,在使用自動拆箱時,必定要確保包裝類的引用不爲空。
上面提到了幾個包裝類的方法,咱們一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沒有自動裝箱池
Java經過自動裝箱和拆箱的機制,節省了部份內存開銷和建立對象的開銷,提升了效率同時簡化了代碼。在使用該機制的時候,須要注意如下幾點: 1.在進行==比較的時候,在自動裝箱池範圍內的數據的引用是相同的,範圍外的是不一樣的。 2。在自動拆箱時,要保證包裝類的引用不爲空。