Integer面試連環炮以及源碼分析

場景:

  昨天有位朋友去面試,我問他面試問了哪些問題,其中問了Integer相關的問題,如下就是面試官問的問題,還有一些是我對此作了擴展。java

問:兩個new Integer 128相等嗎?

答:不。由於Integer緩存池默認是-127-128;面試

問:能夠修改Integer緩存池範圍嗎?如何修改?

答:能夠。使用-Djava.lang.Integer.IntegerCache.high=300設置Integer緩存池大小設計模式

問:Integer緩存機制使用了哪一種設計模式?

答:亨元模式;緩存

問:Integer是如何獲取你設置的緩存池大小?

答:sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");app

問:sun.misc.VM.getSavedPropertySystem.getProperty有啥區別?

答:惟一的區別是,System.getProperty只能獲取非內部的配置信息;例如java.lang.Integer.IntegerCache.highsun.zip.disableMemoryMappingsun.java.launcher.diagsun.cds.enableSharedLookupCache等不能獲取,這些只能使用sun.misc.VM.getSavedProperty獲取源碼分析

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) {
            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() {}
}複製代碼

VM.class源碼分析:

初始化:

static {
    allowArraySyntax = defaultAllowArraySyntax;
    savedProps = new Properties();
    finalRefCount = 0;
    peakFinalRefCount = 0;
    initialize();
}複製代碼

getSavedProperty方法:

public static String getSavedProperty(String var0) {
    if (savedProps.isEmpty()) {
        throw new IllegalStateException("Should be non-empty if initialized");
    } else {
        return savedProps.getProperty(var0);
}    複製代碼

savedProps.getProperty方法:

public String getProperty(String key) {
    Object oval = super.get(key);
    String sval = (oval instanceof String) ? (String)oval : null;
    return ((sval == null) && (defaults != null)) ? defaults.getProperty(key) : sval;
}複製代碼

System.java源碼分析:

/**
 * 初始化系統類。 線程初始化後調用。
 */
private static void initializeSystemClass() {

    /**
     * VM可能會調用JNU_NewStringPlatform()來在「props」初始化期間設置那些編碼敏感屬性(user.home,user.name,boot.class.path等),
     * 它們可能須要經過System.getProperty()進行訪問, 在初始化的早期階段已經初始化(放入「props」)的相關係統編碼屬性。
     * 所以,請確保初始化時可使用「props」,並直接將全部系統屬性放入其中。
     */
    props = new Properties();
    initProperties(props);  // initialized by the VM

    /**
     * 某些系統配置能夠由VM選項控制,例如用於支持自動裝箱的對象標識語義的最大直接內存量和整數高速緩存大小。 一般,庫將得到這些值
     * 來自VM設置的屬性。 若是屬性是
     * 僅限內部實現使用,應從系統屬性中刪除這些屬性。
     *
     *   請參閱java.lang.Integer.IntegerCache和
     *   例如,sun.misc.VM.saveAndRemoveProperties方法。
     *
     *   保存系統屬性對象的私有副本,該副本只能由內部實現訪問。 去掉
     * 某些不適合公共訪問的系統屬性。
     */
    sun.misc.VM.saveAndRemoveProperties(props);


    lineSeparator = props.getProperty("line.separator");
    sun.misc.Version.init();

    FileInputStream fdIn = new FileInputStream(FileDescriptor.in);
    FileOutputStream fdOut = new FileOutputStream(FileDescriptor.out);
    FileOutputStream fdErr = new FileOutputStream(FileDescriptor.err);
    setIn0(new BufferedInputStream(fdIn));
    setOut0(newPrintStream(fdOut, props.getProperty("sun.stdout.encoding")));
    setErr0(newPrintStream(fdErr, props.getProperty("sun.stderr.encoding")));

    /**
     * 如今加載zip庫,以防止java.util.zip.ZipFile稍後嘗試使用它來加載此庫。
     */
    loadLibrary("zip");

    // 爲HUP,TERM和INT(若是可用)設置Java信號處理程序。
    Terminator.setup();

    /**
     * 初始化須要爲類庫設置的任何錯誤的操做系統設置。
     * 目前,除了在使用java.io類以前設置了進程範圍錯誤模式的Windows以外,這在任何地方都是無操做的。
     */
    sun.misc.VM.initializeOSEnvironment();

    /**
     * 主線程沒有像其餘線程同樣添加到其線程組中; 咱們必須在這裏本身作。
     */
    Thread current = Thread.currentThread();
    current.getThreadGroup().add(current);

    // 註冊共享祕密
    setJavaLangAccess();

    /**
     * 在初始化期間調用的子系統能夠調用sun.misc.VM.isBooted(),以免執行應該等到應用程序類加載器設置完畢的事情。
     * 重要信息:確保這仍然是最後一次初始化操做!
     */
    sun.misc.VM.booted();
}複製代碼

重點看這句:sun.misc.VM.saveAndRemoveProperties(props);他會移除系統內部使用的配置,我們來看看源碼是如何操做的。編碼

sun.misc.VM.saveAndRemoveProperties方法:

public static void saveAndRemoveProperties(Properties var0) {
    if (booted) {
        throw new IllegalStateException("System initialization has completed");
    } else {
        savedProps.putAll(var0);
        String var1 = (String)var0.remove("sun.nio.MaxDirectMemorySize");
        if (var1 != null) {
            if (var1.equals("-1")) {
                directMemory = Runtime.getRuntime().maxMemory();
            } else {
                long var2 = Long.parseLong(var1);
                if (var2 > -1L) {
                    directMemory = var2;
                }
            }
        }

        var1 = (String)var0.remove("sun.nio.PageAlignDirectMemory");
        if ("true".equals(var1)) {
            pageAlignDirectMemory = true;
        }

        var1 = var0.getProperty("sun.lang.ClassLoader.allowArraySyntax");
        allowArraySyntax = var1 == null ? defaultAllowArraySyntax : Boolean.parseBoolean(var1);
        //移除內部使用的配置,不該該讓看到這些配置信息
        var0.remove("java.lang.Integer.IntegerCache.high");
        var0.remove("sun.zip.disableMemoryMapping");
        var0.remove("sun.java.launcher.diag");
        var0.remove("sun.cds.enableSharedLookupCache");
    }
}複製代碼
相關文章
相關標籤/搜索