原文參考:http://tangxman.github.io/2015/07/27/the-difference-of-java-string-pool/
字符串常量池(string 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)辟的一塊空間存放的)。string pool在每個(gè)HotSpot VM的實(shí)例只有一份淌实,被所有的類(lèi)共享冻辩。在jdk1.8后,將String常量池放到了堆中拆祈。
class常量池
當(dāng)java文件被編譯成class文件之后恨闪,會(huì)在class文件中生成我們所說(shuō)的class常量池,class文件中除了包含類(lèi)的版本放坏、字段咙咽、方法、接口等描述信息外淤年,還有一項(xiàng)信息就是常量池(constant pool table)钧敞,用于存放編譯器生成的各種字面量(文本字符串、被聲明為final的常量麸粮、基本數(shù)據(jù)類(lèi)型的值)和符號(hào)引用(類(lèi)和接口的全限定名溉苛、字段的名稱(chēng)和描述符、方法的名稱(chēng)和描述符)弄诲。
jvm的方法區(qū)里存放著類(lèi)的版本愚战,字段,方法齐遵,接口和常量池寂玲。常量池里存儲(chǔ)著字面量和符號(hào)引用。
梗摇、
運(yùn)行時(shí)常量池
當(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)字符串常量池,也就是我們上面所說(shuō)的string pool,以保證運(yùn)行時(shí)常量池所引用的字符串與字符串常量池中所引用的是一致的亮蒋。
相關(guān)概念
1扣典、方法區(qū)中的運(yùn)行時(shí)常量池
運(yùn)行時(shí)常量池是方法區(qū)的一部分。
CLass文件中除了有類(lèi)的版本慎玖、字段贮尖、方法、接口等描述信息外趁怔,還有一項(xiàng)信息是常量池湿硝,用于存放編譯期生成的各種字面量和符號(hào)引用,這部分內(nèi)容將在類(lèi)加載后進(jìn)入方法區(qū)的運(yùn)行時(shí)常量池中存放润努。
運(yùn)行時(shí)常量池相對(duì)于CLass文件常量池的另外一個(gè)重要特征是具備動(dòng)態(tài)性关斜,Java語(yǔ)言并不要求常量一定只有編譯期才能產(chǎn)生,也就是并非預(yù)置入CLass文件中常量池的內(nèi)容才能進(jìn)入方法區(qū)運(yùn)行時(shí)常量池铺浇,運(yùn)行期間也可能將新的常量放入池中痢畜,這種特性被開(kāi)發(fā)人員利用比較多的就是String類(lèi)的intern()方法。
2鳍侣、常量池的好處
常量池是為了避免頻繁的創(chuàng)建和銷(xiāo)毀對(duì)象而影響系統(tǒng)性能丁稀,其實(shí)現(xiàn)了對(duì)象的共享。
例如字符串常量池拱她,在編譯階段就把所有的字符串文字放到一個(gè)常量池中二驰。
(1)節(jié)省內(nèi)存空間:常量池中所有相同的字符串常量被合并,只占用一個(gè)空間秉沼。
(2)節(jié)省運(yùn)行時(shí)間:比較字符串時(shí)桶雀,==比equals()快。對(duì)于兩個(gè)引用變量唬复,只用==判斷引用是否相等矗积,也就可以判斷實(shí)際值是否相等。