由裝箱引起的——Integer比較的前因後果

前置知識:兩個對象==比較的是棧的值,"==" 在java中比較對象時永遠是比較對象的地址,這一點毫不會錯。衆所周之,java是保留了int,char等基本數據類型的,也就是說int類型的並非對象,然而有些方法卻須要object 類型的變量,因此java使用了裝箱機制,咱們能夠自豪的這樣聲明一個整型變量:Integer a = new Integer(10); 那麼整型的a也就是對象了,那這句是什麼意思呢:Integer a= 10; java中能夠這樣聲明一個對象嗎?固然不是,從jdk1.5後,java實現了自動裝箱,也就是自動將Integer a =10 中的int類型的10轉化爲了 Integer類型。 java

好,有了前面的只是咱們且先看一個題目:
Integer a = 127;
Integer b = 127;

Integer c = 128;
Integer d = 128;

System.out.println(a==b);
System.out.println(c==d); 數組

答案是什麼呢? 若是您回答true,false,那麼很遺憾的告訴你,你答對了!!! 緩存

分析一下,Integer a =127,Integer a=128。127,128應該不會形成什麼差別吧,難道是自動裝箱的過程有貓膩?找下源碼看看:
private static class IntegerCache {
    private IntegerCache(){
    }
    static final Integer cache[] = new Integer[-(-128) + 127 + 1]; jvm

    static {
        for(int i = 0; i < cache.length; i++)
            cache[i] = new Integer(i - 128);
        }
    }
    public static Integer valueOf(int i) {
        final int offset = 128;
        if (i >= -128 && i <= 127) { // must cache
            return IntegerCache.cache[i + offset];
        }
        return new Integer(i);
    }
}
spa

源碼解釋:當咱們裝箱時,jvm其實是自動調用的valueOf()這個方法,也就是Integer a= 10至關於Integer.valueOf(10)。好,咱們看下Integer a = 127 的執行過程,首先調用Integer.valueOf(127) ,因爲127在-128到127之間(看上面的源碼),因此返回一個緩存值 return IntegerCache.cache[127+128];也就是數組中下標是255的值,那這個究竟是什麼值呢? 咱們繼續看: 對象


static {
        for(int i = 0; i < cache.length; i++)
            cache[i] = new Integer(i - 128);
    } 內存

這是用一個for循環對數組cache賦值,cache[255] = new Integer(255-128),也就是new一個Integer(127) ,並把引用賦值給cache[255],好了,而後是Integer b= 127,流程基本同樣,最後又到了cache[255] = new Integer(255-128),這一句,有點迷糊了,這不是又new了一個對象127嗎,而後把引用賦值給cache[255],咱們比較這兩個引用(前面聲明a的時候也有一個),因爲是不一樣的地址,因此確定不會相等,應該返回false啊!這麼想你就錯了,請注意看for語句給cache[i]初始化的時候外面有一個{},{}前面一個大大的static關鍵字大咧咧的杵在哪呢,對靜態的,那麼咱們就能夠回想下static有什麼特性:
只能初始化一次,在對象間共享,也就是不一樣的對象共享同一個static數據,那麼當咱們Integer b = 127的時候,並無new出一個新對象來,而是共享了a這個對象的引用,記住,他們共享了同一個引用!!!,那麼咱們進行比較a==b時,因爲是同一個對象的引用(它們在堆中的地址相同),那固然返回 true了!!! 源碼

而後咱們在看Integer c = 128;Integer d = 128;,當數據再也不-128到127之間時,是不執行return IntegerCache.cache[i + offset];這句的,也就是不會返回一個static的引用,而是執行了return new Integer(i); 因而當 Integer d = 128 時,又會從新返回一個引用,兩個不一樣的引用
在作c==d 的比較時固然返回false了!! for循環

/*===========================================================*/ class

public static void main(String[] args) {
    Integer a = new Integer(1);
    Integer b = new Integer(1);
    int c=1;
    Integer e = 1;
    System.out.println("a==b:"+(a==b));
    System.out.println("a==c:"+(a==c));
    System.out.println("a==e:"+(a==e));
    System.out.println("c==e:"+(c==e));
}
結果:
a==b:false
a==c:true
a==e:false
c==e:true

Integer是int的封裝對象,兩個對象==比較的是棧的值。
Integer a = new Integer(1);
Integer b = new Integer(1);
a與b在棧中,存的是Integer對象在堆中的地址,而不是值。
a、b指向堆中的地址顯然不一樣因此 a==b 爲false.


int c = 1; int爲值類型,引用類型Integer與值類型int比較顯然比較的是值。
由於int在堆中是不開闢內存的,他在棧中的值則爲他自己的值
因此a==c比較的是他們各自的value, a==c爲true

Integer e=1; 這個比較特殊,直接賦值,它有獨立的內存,每次賦值時將檢查內存中是否有值跟他匹配的,如有則把此內存地址付給e,若沒有,開闢新的內存。

你能夠嘗試下面的例子:
Integer t1 = 1;
Integer t2 = 1;
t1==t2 爲true,如上所說,此時t1與t2指向的是同一塊內存。

new 必定是開闢新的內存,直接賦值則不必定開闢新的內存。
由於a的引用指向堆,而e指向專門存放他的內存,因此他們的內存地址不同。
因此a==e爲false.

c==e等同於 a==c,一個引用類型一個值類型
integer與integer比較的是引用的地址,integer與int,integer先拆箱,比較的是值。

/*==========================================================*/

Integer 在自動裝箱時調用了valueOf() 方法,其中IntegerCache 用來緩存Integer值的。默認緩存的Integer 值範圍是  -128 ~ 127 。
 
咱們來分析一下valueOf(int i)的執行過程:
若是 i 大於緩存中的 最小值(-127) 而且 小於 緩存中的最大值(127),直接返回IntegerCache 中緩存的Integer對象。不然就新建一個Integer對象並返回。

在-128~127之間時,裝箱操做後,a 和 b 都是指向緩存中的同一個對象,結果返回true。其餘狀況下就不同了,裝箱操做時都是返回新的Integer對象,== 操做時地址必然不相等,因此返回false。   之後遇到數字比較時,要麼先將值賦給對應的基本類型在比較,要麼比較包裝類型中的包裝值(例如 a.intValue() == b.intValue()),要麼直接調用equals方法。

相關文章
相關標籤/搜索