天天看點

淺談Integer

今天看到這樣一道題;

class AutoUnboxingTest {

    public static void main(String[] args) {
        Integer a = new Integer(3);
        Integer b = 3;                  // 将3自動裝箱成Integer類型
        int c = 3;
        System.out.println(a == b);     // false 兩個引用沒有引用同一對象
        System.out.println(a == c);     // true a自動拆箱成int類型再和c比較
    }
}
           

從jdk5開始引入了裝箱、拆箱機制,關于Integer中的==,jdk源代碼是這樣寫的:

* @since  1.5
     */
    public static Integer valueOf(int i) {
        assert IntegerCache.high >= 127;
        if (i >= IntegerCache.low && i <= IntegerCache.high)
            return IntegerCache.cache[i + (-IntegerCache.low)];
        return new Integer(i);
    }
           

上面這段代碼首先規定了一個範圍,預設是-128-127之間,如果參數中的i在這個範圍之内,則傳回一個數組中的内容,如果不在這個範圍,則new一個新的Integer對象并傳回。檢視Integer類的源碼可以發現,這個數組裡面緩存了基本類型-128-127之間的Integer對象。顯然:Integerb=3 是将3自動轉型了,而a是直接new了一個對象,開辟了一塊新的堆空間,是以他們的指向位址肯定是不相等的。

在Integer常量池中,Integer隻對包裝了int值在-128-127這個範圍的Integer對象做了共享。這種共享模式叫做享元模式,在所有設計模式中都有各自的優點和缺點,享元模式也不例外。享元模式它的優點在于,通過共享一些對象降低記憶體中相同對象的數量。

但是,想象一下int類型從0x80000000到0x7fffffff如果把所有這些數字包裝成共享對象,那需要的對象的數量将是多麼的龐大,恐怕還不如不進行處理呢,另外在程式中有很多用不上(在項目中從來那沒見那個程式會把所有的int值用個遍的)。

是以Integer隻對包裝了int值在-128-127這個範圍的Integer對象做了共享。如果超過了這個範圍,就會在堆空間上開辟一個新的區域(return new Integer(i);)

再來一道題:

public static void main(String[] args) {
        Integer f1 = 100, f2 = 100, f3 = 150, f4 = 150;

        System.out.println(f1 == f2);
        System.out.println(f3 == f4);
    }
           

   f1==f2,這裡會給f2自動裝箱,因為是在-128-127之間,是以不用new新的對象了,直接引用常量池的對象。故他們指向的是同一個對象,是true;    f3==f4,f3 f4不在-128-127之間,是以各自在堆中開辟新的空間,指向的不是同一對象,為false。

總結    Object類中的equals方法和“==”是一樣的,沒有差別,而String類,Integer類等等一些類,是重寫了equals方法,才使得equals和“==不同”,“==比較位址,equals比較值”。    但是對于包裝類和基本類型,還要涉及它們的自動裝箱、自動拆箱,是以小心一點還是比較好的,不要走到别人挖的陷阱中。

繼續閱讀