Java中的常量池

Java中的常量池分為三類:字符串常量池姜钳、class常量池毛甲、運行時常量池

字符串常量池

從1.7及其之后景东,字符串常量池從方法區(qū)移到了

字符串池的實現(xiàn)——StringTable

String類中并沒有Integer中IntegerCache對象池闻察,String中有native方法intern()邻梆。

intern
intern()方法作用是:若字符串常量池中存在(通過#equals(Object)來判定是否存在)該字符串守伸,則直接返回,否則浦妄,將該String對象添加到池中并返回它的引用尼摹。

/**
     * Returns a canonical representation for the string object.
     * <p>
     * A pool of strings, initially empty, is maintained privately by the
     * class {@code String}.
     * <p>
     * When the intern method is invoked, if the pool already contains a
     * string equal to this {@code String} object as determined by
     * the {@link #equals(Object)} method, then the string from the pool is
     * returned. Otherwise, this {@code String} object is added to the
     * pool and a reference to this {@code String} object is returned.
     * <p>
     * It follows that for any two strings {@code s} and {@code t},
     * {@code s.intern() == t.intern()} is {@code true}
     * if and only if {@code s.equals(t)} is {@code true}.
     * <p>
     * All literal strings and string-valued constant expressions are
     * interned. String literals are defined in section 3.10.5 of the
     * <cite>The Java&trade; Language Specification</cite>.
     *
     * @return  a string that has the same contents as this string, but is
     *          guaranteed to be from a pool of unique strings.
     */
    public native String intern();

intern()

class常量池

class文件是一組以字節(jié)為單位的二進制數(shù)據(jù)流,當java代碼被編譯為.class文件格式時剂娄,二進制數(shù)據(jù)存放在磁盤中蠢涝,其中就包括class文件常量池。

class常量池包含字面量符號引用

image.png

public class HelloWorld {
    public static void main(String[] args) {
        String s = "Hollis";
    }
}

javac 生成HelloWorld.class文件阅懦,然后javap -v HelloWorld.class

常量池內(nèi)容如下:


image.png

Java代碼在編譯時惠赫,并不會“拼接”好完整執(zhí)行文件,而是在虛擬機加載class文件時動態(tài)連接故黑。當虛擬機運行時儿咱,需要從常量池獲得對應的符號引用,再在類創(chuàng)建時或運行時解析场晶、翻譯到具體的內(nèi)存地址中混埠。

運行時常量池

Java1.7之前是在方法區(qū),也處于永久代中诗轻;Java1.7因為使用永久代存在內(nèi)存泄漏問題钳宪,將永久代中的運行時常量池移動到堆內(nèi)存中;Java1.8是在元空間扳炬。

只有class文件中的常量池肯定是不夠的吏颖,因為我們需要在JVM中運行起來。這時候就需要一個運行時常量池恨樟,為JVM的運行服務半醉。
運行時常量池跟class文件的常量池一一對應,它是根據(jù)class常量池來構(gòu)建的劝术。

運行時常量池分兩種類型:符號引用和靜態(tài)常量

String s = "a";

s就是符號引用缩多,需要在運行期進行解析呆奕,而a是靜態(tài)常量,它是不會發(fā)生變化的衬吆。

靜態(tài)常量詳解

運行時常量池中的靜態(tài)常量是從class文件中的constant_pool構(gòu)建的梁钾,可以分為兩部分:String常量和數(shù)字常量。

String常量
String常量是對String對象的引用逊抡,是從class中的CONSTANT_String_info結(jié)構(gòu)構(gòu)建的:

CONSTANT_String_info {
u1 tag;
u2 string_index;
}

tag是結(jié)構(gòu)體的標記姆泻,string_index是string在class常量池中的index。
string_index對應的class常量池的內(nèi)容是一個CONSTANT_Utf8_info結(jié)構(gòu)體冒嫡。

CONSTANT_Utf8_info {
u1 tag;
u2 length;
u1 bytes[length];
}

CONSTANT_Utf8_info是啥呢麦射?它就是要創(chuàng)建的String對象的變種UTF-8編碼。
我們知道unicode的范圍是從0x0000 至 0x10FFFF灯谣。
變種UTF-8就是將unicode進行編碼的方式。那是怎么編碼呢蛔琅?


image.png

上面這個圖說實話胎许,我沒怎么看懂,TODO待學習

CONSTANT_String_info運行時String常量的規(guī)則(inter):

  • 如果String.intern之前被調(diào)用過罗售,并且返回的結(jié)果和CONSTANT_String_info中保存的編碼是一致的話辜窑,表示他們指向的是同一個String的實例。
  • 如果不同的話寨躁,那么會創(chuàng)建一個新的String實例穆碎,并將運行時String常量指向該String的實例。最后會在這個String實例上調(diào)用String的intern方法职恳。調(diào)用inter方法主要是將這個String實例加入字符串常量池所禀。

數(shù)字常量
數(shù)字常量是從class文件中的CONSTANT_Integer_info, CONSTANT_Float_info, CONSTANT_Long_info和 CONSTANT_Double_info 構(gòu)建的。

符號引用詳解
符號引用也是從class中的constant_pool中構(gòu)建的放钦。
對class和interface的符號引用來自于CONSTANT_Class_info色徘。
對class和interface中字段的引用來自于CONSTANT_Fieldref_info。
class中方法的引用來自于CONSTANT_Methodref_info操禀。
interface中方法的引用來自于CONSTANT_InterfaceMethodref_info褂策。
對方法句柄的引用來自于CONSTANT_MethodHandle_info。
對方法類型的引用來自于CONSTANT_MethodType_info颓屑。
對動態(tài)計算常量的符號引用來自于CONSTANT_MethodType_info斤寂。
對動態(tài)計算的call site的引用來自于CONSTANT_InvokeDynamic_info。

參考:https://cloud.tencent.com/developer/article/1450501
http://hollischuang.gitee.io/tobetopjavaer/#/basics/java-basic/class-contant-pool
https://www.cnblogs.com/natian-ws/p/10749164.html
http://hollischuang.gitee.io/tobetopjavaer/#/basics/java-basic/Runtime-Constant-Pool
https://www.cnblogs.com/flydean/p/jvm-run-time-constant-pool.html

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末揪惦,一起剝皮案震驚了整個濱河市遍搞,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌器腋,老刑警劉巖尾抑,帶你破解...
    沈念sama閱讀 218,755評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件歇父,死亡現(xiàn)場離奇詭異,居然都是意外死亡再愈,警方通過查閱死者的電腦和手機榜苫,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來翎冲,“玉大人垂睬,你說我怎么就攤上這事】购罚” “怎么了驹饺?”我有些...
    開封第一講書人閱讀 165,138評論 0 355
  • 文/不壞的土叔 我叫張陵,是天一觀的道長缴渊。 經(jīng)常有香客問我赏壹,道長,這世上最難降的妖魔是什么衔沼? 我笑而不...
    開封第一講書人閱讀 58,791評論 1 295
  • 正文 為了忘掉前任蝌借,我火速辦了婚禮,結(jié)果婚禮上指蚁,老公的妹妹穿的比我還像新娘菩佑。我一直安慰自己,他們只是感情好凝化,可當我...
    茶點故事閱讀 67,794評論 6 392
  • 文/花漫 我一把揭開白布稍坯。 她就那樣靜靜地躺著,像睡著了一般搓劫。 火紅的嫁衣襯著肌膚如雪瞧哟。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,631評論 1 305
  • 那天枪向,我揣著相機與錄音绢涡,去河邊找鬼。 笑死遣疯,一個胖子當著我的面吹牛雄可,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播缠犀,決...
    沈念sama閱讀 40,362評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼数苫,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了辨液?” 一聲冷哼從身側(cè)響起虐急,我...
    開封第一講書人閱讀 39,264評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎滔迈,沒想到半個月后止吁,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體被辑,經(jīng)...
    沈念sama閱讀 45,724評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年敬惦,在試婚紗的時候發(fā)現(xiàn)自己被綠了盼理。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,040評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡俄删,死狀恐怖宏怔,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情畴椰,我是刑警寧澤臊诊,帶...
    沈念sama閱讀 35,742評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站斜脂,受9級特大地震影響抓艳,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜帚戳,卻給世界環(huán)境...
    茶點故事閱讀 41,364評論 3 330
  • 文/蒙蒙 一玷或、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧销斟,春花似錦、人聲如沸椒舵。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽笔宿。三九已至犁钟,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間泼橘,已是汗流浹背涝动。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留炬灭,地道東北人醋粟。 一個月前我還...
    沈念sama閱讀 48,247評論 3 371
  • 正文 我出身青樓,卻偏偏與公主長得像重归,于是被迫代替她去往敵國和親米愿。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,979評論 2 355

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