Integer中valueOf與parseInt區別及其緩存策略

本文來聊一下Integer中的兩個常用的靜態方法valueOfparseInt,順便引出基本類型包裝類的緩存策略

前言

這篇文章的想法來源於一次代碼檢查,使用findbugs插件檢查代碼,然後報瞭如下信息(不屬於bug,但是是一個更好的建議)

A boxed primitive is created from a String, just to extract the unboxed primitive value. It is more efficient to just call the static parseXXX method.

大致意思就是說把String類型轉換成了包裝類,而參數需要的是基本類型值,所以用parseXXX方法更有效。說實話這些方法很常用,也比較簡單,就沒有去看過它們到底有什麼區別,直到這次偶然的機會。

源碼分析

先來看下面這兩個方法

public static Integer valueOf(String s) throws NumberFormatException {
    return Integer.valueOf(parseInt(s, 10));
}

public static Integer valueOf(int i) {
    if (i >= IntegerCache.low && i <= IntegerCache.high)
        return IntegerCache.cache[i + (-IntegerCache.low)];
    return new Integer(i);
}

可以看到將字符串類型轉換爲Integer對象實則就是先去調用了parseInt(String s, int radix)方法,轉換爲int基本類型後,再包裝爲Integer對象。

看到這裏其實就已經解釋了上述findbugs的問題,但是可以發現,valueOf方法中先進行了範圍判斷,通過 IntegerCache 這個類名我們可以知道,這裏做了緩存。

接下來先做個無獎競猜,猜猜下面兩行分別輸出什麼

System.out.println(Integer.valueOf(100) == Integer.valueOf(100));
System.out.println(Integer.valueOf(200) == Integer.valueOf(200));

相信即使不熟悉的同學看到這裏也必然知道有坑哈哈,結果自己驗證下就曉得了
那麼就來看下 IntegerCache 到底做了什麼

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() {}
}

Integer中默認緩存範圍爲-128~127,新建一個數組,通過for循環緩存範圍內的Integer對象。
緩存最大值是可以通過設置

-Djava.lang.Integer.IntegerCache.high=xxx

來進行修改,該緩存會在首次使用Integer時初始化。
說到底這裏做緩存是爲了節省內存,提高性能,默認-128~127的範圍是因爲該範圍內的數字使用頻率較高。

那麼既然Integer類有緩存,其他基本類型的包裝類是否也做了緩存呢?
去看一下其他包裝類的代碼,答案是肯定的
Byte Short Long Character 都做了緩存,前三個範圍固定都是-128~127
Character 緩存範圍爲0~127
並且只有IntegerCache的緩存範圍可配置

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