java Integer類的裝箱拆箱解讀

這是一個面試經常遇到的一個問題,先來看幾個例子:
例1:

Integer i1=1234;
int i2=1234;
System.out.println(i1==i2);

輸出結果爲: true.
例2:

Integer i1=213;
Integer i2=213;
System.out.println(i1==i2);

輸出結果爲:false. 這是爲什麼呢?
例3:

Integer i1=127;
Integer i2=127;
System.out.println(i1==i2);

輸出結果爲:true.這又是爲什麼呢?
例4:

Integer i1=213;
Integer i2=new Integer(213);
System.out.println(i1==i2);

輸出結果爲:false;
例5:

Integer i1=123;
Integer i2=new Integer(123);
System.out.println(i1==i2);

輸出結果爲:false;

原因分析:
首先我們回到標題說一下JAVA的裝箱拆箱:意思是當java程序需要將Integer類型當做int類型使用時,需要拆箱,將Integer類裏的值取出來,作爲一個int類型的值。我們知道java爲每種基本數據類型都編寫了一個封裝類: byte,char,short,int ,long,float,double這幾種基本數據類型都對應一個封裝類:Byte,Short,Character,Short,Integer,Long,Float,Double. 我們現在專就Integer類與int做討論,其他類似。

Integer類有一個域value,代表了該Integer對象的int值。當Integer對象需要當做Int類型時,就將其拆箱,取出這個value。這就是拆箱。裝箱過程與拆箱相反:當我們需要一個Integer對象時,可以直接使用: Integer var=xxx. java的裝箱就是通過方法: Integer Integer.valueOf(int xxx)返回一個數值爲xxx的Integer對象。

接下來看例1:
第1行代碼:用一個Integer i1=1234;等價與執行了:Integer i1 = Integer.valueOf(1234);//裝箱
第3行代碼: 當Integer需要和int比較時,首先將Integer轉成Int,這就是拆箱,取出其Int值,兩個int值都爲1234,所以相等,輸出true;

在分析例2之前首先了解Integer類的valueOf方法實現機制:

 public static Integer valueOf(int i) {
        assert IntegerCache.high >= 127;
        if (i >= IntegerCache.low && i <= IntegerCache.high)
            return IntegerCache.cache[i + (-IntegerCache.low)];//其中IntegerCache.low=-128,IntegerCache.high=127
        return new Integer(i);
    } 

從代碼中可以看出:當i>=127或者小於-128時,new Integer(i),返回的是通過new 出來的一個值爲i的Integer對象。而當i在-128到127之間是,返回的是一個IntegerCache.cache[]數組中的對應Integer對象,下面我們再來看看IntegerCache類在Integer類中的實現機制。

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) {
                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);
            }
            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() {}
    }
  //這是Integer類中的一個私有靜態類,所以所有Integer對象都應該共享着這一個類(雖然看不見(private))。該類的構造方法被私有化了,所以不能實例化該類。該類的其他代碼全部是靜態的,所以所有Integer對象都共享這這個類的每個域。在這裏我們看到了Integer cache[]這個數組,而且該類在加載時就已經實例化了cache數組,chache數組是Integer類型的,每個元素都是一個Intger對象,並且數組第0個元素是值爲-128的Integer對象,數組最後一個元素是值爲127的Integer對象。回到valueOf方法中,當valueOf接受的參數在-128到127之間時,直接會返回該參數在cache數組中對應的那個Integer對象。否則new 一個Integer對象。

通過上面的解析,我們就自然明白了例2到例5的結果:
例2:
因爲 Integer i1=213執行了Integer.valueOf(213),而由於213不在-128到127之間,所以就new Integer(213)並將該對象返回,同理,Integer i2=213實質也是 new Integer(213).由於兩個new Integer(213)並不是同一個對象(內存地址肯定不一樣,只是值一樣罷了),所以i1==i2當然爲false了,因爲==比較的是內存地址。
例3:
因爲127在-128到127之間,所以Integer.valueOf(127)返回的是 IntegerCache.cahe數組中對應值爲127的那個元素,所以i1 和i2都指向的是同一個Integer對象(IntegerCache.cache是所有Integer對象共享的),所以i1==i2就是true;
例4和例5就很好理解了:一個是new出來的Integer對象,另一個要麼是cache數組裏的Integer對象,或者是new出來的,反正實質都是兩個new出來的Integer對象比較,內存地址肯定不一樣,所以值都爲false.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章