java常量池

學(xué)習(xí)和使用java已經(jīng)有4年多了,反省一下,太多關(guān)注了實(shí)際的應(yīng)用層面,對某些基礎(chǔ)的東西沒有特別理解透徹。好記性不如爛筆頭,記錄下一些基礎(chǔ)的知識點(diǎn),把基礎(chǔ)夯實(shí),才能更進(jìn)一步。

先引用一下java常量池的說明:
常量池在java用于保存在編譯期已確定的,已編譯的class文件中的一份數(shù)據(jù)。它包括了關(guān)于類,方法,接口等中的常量,也包括字符串常量,如String s = “java”這種申明方式;當(dāng)然也可擴(kuò)充,執(zhí)行器產(chǎn)生的常量也會放入常量池,故認(rèn)為常量池是JVM的一塊特殊的內(nèi)存空間。

java是一種動態(tài)鏈接的語言,常量池的作用非常重要,常量池中除了包含代碼中所定義的各種基本類型(如int、long等等)和對象型(如String及數(shù)組)的常量值外,還包含一些以文本形式出現(xiàn)的符號引用,比如:
類和接口的全限定名;字段的名稱和描述符;方法的名稱和描述符。

對于程序員來說,這樣的說明略顯枯燥和抽象,我們還是用代碼來說明一切:

Integer i1 = new Integer(1);
Integer i2 = new Integer(1);
System.out.println(i1 == i2); // false

Integer i3 = 1;
Integer i4 = 1;
System.out.println(i3 == i4); // true

對于上面的i1和i2指向的對象,都是用new關(guān)鍵字來創(chuàng)建的,那么2個(gè)實(shí)際的對象都創(chuàng)建在堆內(nèi)存上,就是說,i1和i2分別指向了堆內(nèi)存上的2個(gè)地址,那么用==來比較的時(shí)候,肯定返回false了。對于i3和i4,是直接指定了值,這時(shí)候,java虛擬機(jī)會先到常量池里面去找,如果找到了,就返回對應(yīng)的引用;如果沒找到,那么就重新在堆內(nèi)存上創(chuàng)建,類似于new。

那么,對于上面的Integer,多大的范圍內(nèi)數(shù)會在常量池中存在呢?我們打開Integer類的源碼,發(fā)現(xiàn)它其實(shí)是使用了一個(gè)內(nèi)部類IntegerCache來實(shí)現(xiàn)這個(gè)功能的:

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) {
            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);
        }
        high = h;
        cache = new Integer[(high - low) + 1];
        int j = low;
        for(int k = 0; k < cache.length; k++)
            cache[k] = new Integer(j++);
    }
    private IntegerCache() {}
}

不難看出來,當(dāng)數(shù)值在-128—127的時(shí)候,會從常量池中取得。當(dāng)然,我們自己寫代碼驗(yàn)證一下,會更好:

Integer i5 = 127;
Integer i6 = 127;
System.out.println(i5 == i6); // true

Integer i7 = 128;
Integer i8 = 128;
System.out.println(i7 == i8); // false

類似的,其他幾種基本數(shù)據(jù)類型和對應(yīng)的封裝類類都有使用常量池,不過,float和double沒有,其實(shí)也比較容易理解,如果這2中在常量池中要有,那要放哪些值呢?如果是Integer,那么-128—127明顯比其他的值更加常用,把這些放在常量池中比較合理,但是對于浮點(diǎn)數(shù),就沒有明顯證據(jù)表明哪幾個(gè)更加常用了。

其實(shí)除了基本數(shù)據(jù)類型之外,還有一種對象在java中很常用,也會用到常量池,就是String。提到String類和常量池,必須提到String的一個(gè)native方法:intern()。intern方法會返回String對象的在常量池中的引用,如果在常量池中已經(jīng)存在這個(gè)字符串了,那么直接返回這個(gè)引用;如果沒有,就先把這個(gè)字符串復(fù)制到常量池,然后返回引用。依然通過代碼來說明:

String s1 = new String("java");
String s2 = "java";
System.out.println(s1 == s2); // false
System.out.println(s1.intern() == s2); // true
String常量池
備注:

1、以上的源碼都來自JDK1.7,不同版本的JDK可能會有不同。
2、運(yùn)行環(huán)境為java自帶的hotspot虛擬機(jī),如果執(zhí)行其他虛擬機(jī),由于實(shí)現(xiàn)機(jī)理可能不同,運(yùn)行結(jié)果也可能不同。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • 一.相關(guān)概念 什么是常量用final修飾的成員變量表示常量,值一旦給定就無法改變!final修飾的變量有三種:靜態(tài)...
    夢工廠閱讀 58,137評論 38 277
  • 相關(guān)概念 常量池的定義常量池(constant pool):指的是在編譯期被確定,并被保存在已編譯的.class文...
    snoweek閱讀 814評論 0 4
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法,類相關(guān)的語法,內(nèi)部類的語法,繼承相關(guān)的語法,異常的語法,線程的語...
    子非魚_t_閱讀 31,739評論 18 399
  • 若要人拿真心待自己請相同的誠意對待別人 , 雖然這時(shí)代 通常他人不會同等正能量回對自己 , 對方不修德修福 , 那...
    文時(shí)衍書閱讀 415評論 0 1
  • Hi,老鐵們好啊,前些天說到了科隆國際游戲展這次開展了吃雞比賽,對于絕地求生大逃殺這個(gè)游戲來說,可以說是第一次正式...
    f7246e999e03閱讀 509評論 0 0