Java高級之自動拆箱與自動裝箱

序. java基本類型介紹

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)。程序員

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

自動裝箱:把基本類型用它們對應的包裝類包裝起來,使它們具備對象的特質,能夠調用所對應的包裝類所定義的方法,好比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的話,是不能夠這樣寫的。指針

2.爲何會有自動拆箱與自動裝箱

爲何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對象。

那麼,爲何要這麼設計呢?通常來講,小數字的使用頻率很高,將小數字保存起來,讓其始終僅有一個對象能夠節約內存,提升效率。

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

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。在自動拆箱時,要保證包裝類的引用不爲空。 

相關文章
相關標籤/搜索