日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程语言 > java >内容正文

java

Java中几种常量池的区分

發(fā)布時(shí)間:2023/12/3 java 45 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Java中几种常量池的区分 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

轉(zhuǎn)載自??Java中幾種常量池的區(qū)分

在java的內(nèi)存分配中,經(jīng)常聽(tīng)到很多關(guān)于常量池的描述,我開(kāi)始看的時(shí)候也是看的很模糊,網(wǎng)上五花八門(mén)的說(shuō)法簡(jiǎn)直太多了,最后查閱各種資料,終于算是差不多理清了,很多網(wǎng)上說(shuō)法都有問(wèn)題,筆者嘗試著來(lái)區(qū)分一下這幾個(gè)概念。

1.全局字符串池(string pool也有叫做string literal pool)

全局字符串池里的內(nèi)容是在類(lèi)加載完成,經(jīng)過(guò)驗(yàn)證,準(zhǔn)備階段之后在堆中生成字符串對(duì)象實(shí)例,然后將該字符串對(duì)象實(shí)例的引用值存到string pool中(記住:string pool中存的是引用值而不是具體的實(shí)例對(duì)象,具體的實(shí)例對(duì)象是在堆中開(kāi)辟的一塊空間存放的。)。 在HotSpot VM里實(shí)現(xiàn)的string pool功能的是一個(gè)StringTable類(lèi),它是一個(gè)哈希表,里面存的是駐留字符串(也就是我們常說(shuō)的用雙引號(hào)括起來(lái)的)的引用(而不是駐留字符串實(shí)例本身),也就是說(shuō)在堆中的某些字符串實(shí)例被這個(gè)StringTable引用之后就等同被賦予了”駐留字符串”的身份。這個(gè)StringTable在每個(gè)HotSpot VM的實(shí)例只有一份,被所有的類(lèi)共享。

2.class文件常量池(class constant pool)

我們都知道,class文件中除了包含類(lèi)的版本、字段、方法、接口等描述信息外,還有一項(xiàng)信息就是常量池(constant pool table),用于存放編譯器生成的各種字面量(Literal)和符號(hào)引用(Symbolic References)。 字面量就是我們所說(shuō)的常量概念,如文本字符串、被聲明為final的常量值等。 符號(hào)引用是一組符號(hào)來(lái)描述所引用的目標(biāo),符號(hào)可以是任何形式的字面量,只要使用時(shí)能無(wú)歧義地定位到目標(biāo)即可(它與直接引用區(qū)分一下,直接引用一般是指向方法區(qū)的本地指針,相對(duì)偏移量或是一個(gè)能間接定位到目標(biāo)的句柄)。一般包括下面三類(lèi)常量:

  • 類(lèi)和接口的全限定名
  • 字段的名稱(chēng)和描述符
  • 方法的名稱(chēng)和描述符

常量池的每一項(xiàng)常量都是一個(gè)表,一共有如下表所示的11種各不相同的表結(jié)構(gòu)數(shù)據(jù),這每個(gè)表開(kāi)始的第一位都是一個(gè)字節(jié)的標(biāo)志位(取值1-12),代表當(dāng)前這個(gè)常量屬于哪種常量類(lèi)型。?每種不同類(lèi)型的常量類(lèi)型具有不同的結(jié)構(gòu),具體的結(jié)構(gòu)本文就先不敘述了,本文著重區(qū)分這三個(gè)常量池的概念(讀者若想深入了解每種常量類(lèi)型的數(shù)據(jù)結(jié)構(gòu)可以查看《深入理解java虛擬機(jī)》第六章的內(nèi)容)。

3.運(yùn)行時(shí)常量池(runtime constant pool)

當(dāng)java文件被編譯成class文件之后,也就是會(huì)生成我上面所說(shuō)的class常量池,那么運(yùn)行時(shí)常量池又是什么時(shí)候產(chǎn)生的呢?

jvm在執(zhí)行某個(gè)類(lèi)的時(shí)候,必須經(jīng)過(guò)加載、連接、初始化,而連接又包括驗(yàn)證、準(zhǔn)備、解析三個(gè)階段。而當(dāng)類(lèi)加載到內(nèi)存中后,jvm就會(huì)將class常量池中的內(nèi)容存放到運(yùn)行時(shí)常量池中,由此可知,運(yùn)行時(shí)常量池也是每個(gè)類(lèi)都有一個(gè)。在上面我也說(shuō)了,class常量池中存的是字面量和符號(hào)引用,也就是說(shuō)他們存的并不是對(duì)象的實(shí)例,而是對(duì)象的符號(hào)引用值。而經(jīng)過(guò)解析(resolve)之后,也就是把符號(hào)引用替換為直接引用,解析的過(guò)程會(huì)去查詢(xún)?nèi)肿址?#xff0c;也就是我們上面所說(shuō)的StringTable,以保證運(yùn)行時(shí)常量池所引用的字符串與全局字符串池中所引用的是一致的。

舉個(gè)實(shí)例來(lái)說(shuō)明一下:

1 2 3 4 5 6 7 8String str1 = "abc"; String str2 = new String("def"); String str3 = "abc"; String str4 = str2.intern(); String str5 = "def"; System.out.println(str1 == str3);//true System.out.println(str2 == str4);//false System.out.println(str4 == str5);//true

上面程序的首先經(jīng)過(guò)編譯之后,在該類(lèi)的class常量池中存放一些符號(hào)引用,然后類(lèi)加載之后,將class常量池中存放的符號(hào)引用轉(zhuǎn)存到運(yùn)行時(shí)常量池中,然后經(jīng)過(guò)驗(yàn)證,準(zhǔn)備階段之后,在堆中生成駐留字符串的實(shí)例對(duì)象(也就是上例中str1所指向的”abc”實(shí)例對(duì)象),然后將這個(gè)對(duì)象的引用存到全局String Pool中,也就是StringTable中,最后在解析階段,要把運(yùn)行時(shí)常量池中的符號(hào)引用替換成直接引用,那么就直接查詢(xún)StringTable,保證StringTable里的引用值與運(yùn)行時(shí)常量池中的引用值一致,大概整個(gè)過(guò)程就是這樣了。

回到上面的那個(gè)程序,現(xiàn)在就很容易解釋整個(gè)程序的內(nèi)存分配過(guò)程了,首先,在堆中會(huì)有一個(gè)”abc”實(shí)例,全局StringTable中存放著”abc”的一個(gè)引用值,然后在運(yùn)行第二句的時(shí)候會(huì)生成兩個(gè)實(shí)例,一個(gè)是”def”的實(shí)例對(duì)象,并且StringTable中存儲(chǔ)一個(gè)”def”的引用值,還有一個(gè)是new出來(lái)的一個(gè)”def”的實(shí)例對(duì)象,與上面那個(gè)是不同的實(shí)例,當(dāng)在解析str3的時(shí)候查找StringTable,里面有”abc”的全局駐留字符串引用,所以str3的引用地址與之前的那個(gè)已存在的相同,str4是在運(yùn)行的時(shí)候調(diào)用intern()函數(shù),返回StringTable中”def”的引用值,如果沒(méi)有就將str2的引用值添加進(jìn)去,在這里,StringTable中已經(jīng)有了”def”的引用值了,所以返回上面在new str2的時(shí)候添加到StringTable中的 “def”引用值,最后str5在解析的時(shí)候就也是指向存在于StringTable中的”def”的引用值,那么這樣一分析之后,下面三個(gè)打印的值就容易理解了。

總結(jié)

  • 1.全局常量池在每個(gè)VM中只有一份,存放的是字符串常量的引用值。
  • 2.class常量池是在編譯的時(shí)候每個(gè)class都有的,在編譯階段,存放的是常量的符號(hào)引用。
  • 3.運(yùn)行時(shí)常量池是在類(lèi)加載完成之后,將每個(gè)class常量池中的符號(hào)引用值轉(zhuǎn)存到運(yùn)行時(shí)常量池中,也就是說(shuō),每個(gè)class都有一個(gè)運(yùn)行時(shí)常量池,類(lèi)在解析之后,將符號(hào)引用替換成直接引用,與全局常量池中的引用值保持一致。
? ? ? ? ?

總結(jié)

以上是生活随笔為你收集整理的Java中几种常量池的区分的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。