JDK源碼學習一--Integer、Long、Float、Double基本數據類的緩存

1.Integer、Long、Float、Double基本數據類

問題來源:今天偶然看到了Integer.valueOf()方法,而查看資料顯示【.valueof()是一個靜態方法,同時調用幾次該方法來創建Integet對象,最終都是調用到同一個Integer實例。】
由於對jdk的api實現不熟悉,所以不明白這些是怎麼做到的。因此我編寫一個例子進行一下驗證:

Integer a = Integer.valueof(10);
Integer b = Integer.valueof(10);
Integer c = null;
c=10;
a=11;

最後我在 c = 10;處打下斷點,查看各個對象的id號,發現實例a、b、c三個都是同一個實例id號,因此就表示a、b、c 是同一個對象。
這種結果正好符合資料上面的描述。當我把a=11;重新設置值時,對象a的實例id變成新的id號了,這樣就相當於重新實例了一個Integer對象。
這種現象我沒有弄明白,按照正常的思維來分析,a=11;這句代碼應該只是把Integer實例中的value屬性重設一下值,爲什麼會重新實例一個新的
Integer對象呢?是在沒弄明白,所以只好去查看jdk 1.5 API源代碼。
打開Integer類,裏面的方法讓我大開眼界,發現自己和大師級別人物的差距太大了,所以以後要繼續好好學習,追隨他們,直至超越(低調...)
根據上面的【問題來源】我有一下幾個問題需要通過jdk的源碼來解答疑惑。
1.爲什麼調用a、b、c這三個變量調用Integer.valueof()會得到同一個實例?
2.爲什麼c=10;也會自動變成一個等同於a、b的實例?
3.爲什麼執行a=11;之後會產生一個新的Ingeter對象?
抱着疑問去看東西,永遠是最有效果的。
打開Integer類,就讓我看到了一句代碼,不得其解。
public static final Class<Integer> TYPE = (Class<Integer>) Class.getPrimitiveClass("int");

4.這句代碼的意思不是很清楚,也不知道TYPE到底有啥作用,問題是Class.getPrimitiveClass()這個方法我在jdk1.5 api文檔裏面都沒有找到。
這個問題先放下,不影響我對上面三個問題的解答。

問題一解答:
爲什麼調用Integer.valueof()會得到同一個實例,只好去查找valueof()方法。方法代碼如下:

public static Integer valueOf(int i) {
final int offset = 128;
if (i >= -128 && i <= 127) { // must cache 該處只能緩存-128~127的數據,超出這個範圍的就都是新實例化Ingeter對象。
    return IntegerCache.cache[i + offset];
}
        return new Integer(i);
    }



IntegerCache是Integer類的一個成員內部類,代碼如下:
public final class Integer extends Number implements Comparable<Integer> {
… …
private static class IntegerCache {
private IntegerCache(){}

static final Integer cache[] = new Integer[-(-128) + 127 + 1];//靜態設置一個存儲Integer的數組,就是一個cache
//初始化這個cache,你會發現這個cache裏面只緩存了-128~127這個範圍的Integer實例。
static {
    for(int i = 0; i < cache.length; i++)
cache[i] = new Integer(i - 128);
}
    }

… …
}

按照源代碼的邏輯來推斷,只有在數值屬於(-128~127)這個範圍類的數據,調用Integer.valueof(輸入的數值)纔會使用緩存中已實例化好的對象。
超出這個範圍的數據都是新實例化的對象。接下來就驗證這個結論:

Integer e = Integer.valueof(128);
Integer f = Integer.valueof(128);


驗證發現:果然e、f的實例號不一樣。說明不在(-128~127)範圍內的數據調用Integer.valueof()是產生新的實例。




自動裝箱與拆箱的功能事實上是編譯器來幫您的忙,編譯器在編譯時期依您所編寫的語法,決定是否進行裝箱或拆箱動作。在自動裝箱時對於值從-128到127之間的值,它們被裝箱爲Integer對象後,會存在內存中被重用,所以範例4.6中使用==進行比較時,i1 與 i2實際上參考至同一個對象。如果超過了從-128到127之間的值,被裝箱後的Integer對象並不會被重用,即相當於每次裝箱時都新建一個Integer對象,所以範例4.7使用==進行比較時,i1與i2參考的是不同的對象。所以不要過分依賴自動裝箱與拆箱,您還是必須知道基本數據類型與對象的差異。

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