欧美一级特黄大片做受成人-亚洲成人一区二区电影-激情熟女一区二区三区-日韩专区欧美专区国产专区

JVM字符串常量池及String的intern方法是什么樣的

這篇文章給大家介紹JVM字符串常量池及String的intern方法是什么樣的,內(nèi)容非常詳細(xì),感興趣的小伙伴們可以參考借鑒,希望對(duì)大家能有所幫助。

北塔ssl適用于網(wǎng)站、小程序/APP、API接口等需要進(jìn)行數(shù)據(jù)傳輸應(yīng)用場(chǎng)景,ssl證書(shū)未來(lái)市場(chǎng)廣闊!成為創(chuàng)新互聯(lián)的ssl證書(shū)銷(xiāo)售渠道,可以享受市場(chǎng)價(jià)格4-6折優(yōu)惠!如果有意向歡迎電話(huà)聯(lián)系或者加微信:028-86922220(備注:SSL證書(shū)合作)期待與您的合作!

關(guān)于字符串的比較在前面文章中已經(jīng)詳解過(guò),本篇文章基于字符串常量池的存儲(chǔ)及在使用intern方法時(shí)所引起的內(nèi)存變化進(jìn)行一步深層次的講解。

重點(diǎn)內(nèi)容:當(dāng)字符串調(diào)用intern方法后,再進(jìn)行字符串的比較,會(huì)發(fā)生什么變化?

面試題

先通過(guò)一個(gè)面試題形象的了解一下我們本篇文章要講的內(nèi)容的呈現(xiàn)形式:

String s1 = new String("he") + new String("llo");
String s2 = new String("h") + new String("ello");

String s3 = s1.intern();
String s4 = s2.intern();
System.out.println(s1 == s3);
System.out.println(s1 == s4);

執(zhí)行上面的代碼,會(huì)發(fā)現(xiàn)打印的結(jié)果都是true。那么,為什么本來(lái)不相等的字符串,調(diào)用了intern方法之后便相等了呢?下面我們就來(lái)逐步分析這其中的底層實(shí)現(xiàn)。

intern方法的作用

intern()方法的功能定義:

(1)如果當(dāng)前字符串內(nèi)容存在于字符串常量池(即equals()方法為true,也就是內(nèi)容一樣),那直接返回此字符串在常量池的引用;

(2)如果當(dāng)前字符串不在字符串常量池中,那么在常量池創(chuàng)建一個(gè)引用并指向堆中已存在的字符串,然后返回常量池中的引用。

簡(jiǎn)單說(shuō)intern方法就是判斷并將字符串是否存在于字符串常量池,如果不存在則創(chuàng)建,存在則返回。

字符串常量池

在HotSpot中實(shí)現(xiàn)字符串常量池功能的是一個(gè)StringTable類(lèi),它是一個(gè)Hash表,默認(rèn)值大小長(zhǎng)度是1009。在每個(gè)HotSpot虛擬機(jī)的實(shí)例中只有一份,被所有的類(lèi)共享。字符串常量由一個(gè)個(gè)字符組成,放在了StringTable上。

在《面試題系列第5篇:JDK的運(yùn)行時(shí)常量池、字符串常量池、靜態(tài)常量池,還傻傻分不清?》一文中我們已經(jīng)專(zhuān)門(mén)介紹了字符串常量池的位置隨著JDK版本的變化而變化,可以參考。

JDK6及之前版本,字符串常量池是放在Perm Gen區(qū)(方法區(qū))中。StringTable的長(zhǎng)度是固定的,長(zhǎng)度是1009,當(dāng)String字符串過(guò)多時(shí)會(huì)造成hash沖突,導(dǎo)致鏈表過(guò)長(zhǎng),性能大幅度下降。此時(shí)字符串常量池里面放的全部是字符串常量(字面值)。

由于永久代的空間有限且固定,JDK6的存儲(chǔ)模式很容易造成OutOfMemoryError。

而JDK7時(shí)正在著手去永久代的工作,因此字符串常量池被放在了堆中。此時(shí),即使堆的大小也是固定的,但對(duì)于應(yīng)用調(diào)優(yōu)工作,只需要調(diào)整堆大小就行了。

在JDK7中字符串常量池不僅僅可以存放字符串常量,還可以存放字符串的引用。也就是說(shuō),堆中的字符串的引用可以作為常量池的值而存在。

字符串池化流程分析

在了解了上面的基礎(chǔ)理論,我們下面以圖文相結(jié)合的形式來(lái)逐步演示字符串池化的流程和分類(lèi)。以下實(shí)例以JDK8版本為基礎(chǔ)來(lái)進(jìn)行分析講解。

當(dāng)我們通過(guò)雙引號(hào)聲明一個(gè)字符串:

String wechat = "程序新視界";

此時(shí),雙引號(hào)內(nèi)的字符串會(huì)被直接存儲(chǔ)在字符串常量池中。

JVM字符串常量池及String的intern方法是什么樣的

關(guān)于上面的存儲(chǔ)結(jié)構(gòu),我們已經(jīng)在之前文章中提到,不再過(guò)多解釋。下面如果我們?cè)俾暶魍瑯拥淖址纯磿?huì)有什么樣的變化。

String wechat = "程序新視界";
String wechat1 = "程序新視界";

上述代碼中聲明wechat1時(shí),會(huì)發(fā)現(xiàn)常量池中已經(jīng)存在了對(duì)應(yīng)的字符串,則不會(huì)再重新創(chuàng)建,只是把對(duì)應(yīng)的引用返回給wechat1。對(duì)應(yīng)結(jié)構(gòu)圖如下: JVM字符串常量池及String的intern方法是什么樣的

此時(shí),如果直接用雙等號(hào)比較wechat和wechat1肯定是相等的,因?yàn)樗鼈兊囊煤妥置嬷刀际窍嗤摹?/p>

上面是直接雙引號(hào)賦值的情況,那么如果通過(guò)new的形式創(chuàng)建字符串對(duì)應(yīng)的流程又是如何呢?前面文章已經(jīng)講到這分兩種情況:常量池存在對(duì)應(yīng)的值和不存在對(duì)應(yīng)的值。

String wechat2 = new String("程序新視界");

如果存在對(duì)應(yīng)的值,此時(shí)會(huì)先在堆中創(chuàng)建一個(gè)針對(duì)wechat2變量的對(duì)象引用,然后將這個(gè)對(duì)象引用指向字符串常量池中已經(jīng)存在的常量。 JVM字符串常量池及String的intern方法是什么樣的

此時(shí)直接使用雙等號(hào)比較wechat和wechat2變量肯定是不相等的,而通過(guò)equals方法進(jìn)行對(duì)比字面值則是相等的。

另外一種情況就是通過(guò)new創(chuàng)建時(shí),字符串常量池中并不存在對(duì)應(yīng)的常量。這種情況會(huì)現(xiàn)在字符串常量池中創(chuàng)建一個(gè)字符串常量,然后再在堆中創(chuàng)建一個(gè)字符串,持有常量池中對(duì)應(yīng)字符串的引用。并把堆中對(duì)象的地址返回給wechat2。最終效果圖依舊如上圖。

在此時(shí),如果不是直接new字符串賦值,而是通過(guò)+號(hào)操作,情況就有所不同。

String s1 = "程序";
String wechat3 = new String(s1 + "新視界");

上述代碼s1會(huì)存入常量池,而wechat3的值則由于JVM編譯時(shí)采用了StringBuilder進(jìn)行加號(hào)的拼接,只會(huì)在堆中創(chuàng)建一個(gè)String對(duì)象,并不會(huì)在常量池中存儲(chǔ)對(duì)應(yīng)的字符串。

JVM字符串常量池及String的intern方法是什么樣的

此時(shí)的情況已經(jīng)涉及到我們面試題中創(chuàng)建字符串的情況了。那么,下面我們就通過(guò)intern方法進(jìn)行池化操作,看看字符串常量池的具體變化。

還以上面的代碼為例,此時(shí)wechat、wechat1、wechat2三個(gè)變量和wechat3直接用雙等號(hào)比較肯定是不相等的。下面對(duì)wechat3進(jìn)行intern池化處理。

String s1 = "程序";
String wechat3 = new String(s1 + "新視界");
wechat3 = wechat3.intern();

此時(shí)會(huì)發(fā)現(xiàn)wechat、wechat1兩個(gè)變量與wechat3的值相等了。由于wechat和wechat1其實(shí)是一個(gè),這里只以wechat和wechat3的比較為例來(lái)分析一下這個(gè)流程。

在沒(méi)有調(diào)用intern方法之前內(nèi)存的狀態(tài)是下圖(忽略掉s1部分)這樣的:

JVM字符串常量池及String的intern方法是什么樣的

看上圖它們的值不相等也就不奇怪了。下面對(duì)wechat3進(jìn)行池化處理,并把池化的結(jié)果賦值給wechat3,就是上面的代碼。內(nèi)存結(jié)構(gòu)會(huì)發(fā)生如下變化:

JVM字符串常量池及String的intern方法是什么樣的

此時(shí),再判斷對(duì)應(yīng)的兩個(gè)值,因?yàn)橐煤妥置嬷等肯嗤?,因此便相等了。具體intern的判斷規(guī)則我們上面已經(jīng)知道,如果常量池中存在對(duì)應(yīng)的值,則直接返回引用。

那還有另外一種情況,就是常量池中不存在對(duì)應(yīng)的值會(huì)是如何處理的呢?先看如下代碼:

String s2 = "關(guān)注";
String wechat4 = new String(s2 + "公眾號(hào)");
wechat4 = wechat4.intern();

在調(diào)用intern之前的操作我們前面已經(jīng)說(shuō)過(guò),會(huì)在堆中創(chuàng)建一個(gè)String對(duì)象,而常量池中并不會(huì)存儲(chǔ)一份,與wechat3的圖一樣。

此時(shí)常量池中并未存在對(duì)應(yīng)的字符串,此時(shí)調(diào)用intern方法之后,內(nèi)存結(jié)構(gòu)如下:

JVM字符串常量池及String的intern方法是什么樣的

經(jīng)intern方法之后,常量池中存了堆中對(duì)應(yīng)字符串的引用。對(duì)照上面說(shuō)的,JDK7及之后字符串常量池中可以存儲(chǔ)引用了。

需要注意的是,當(dāng)字符串常量池中并不存在對(duì)應(yīng)字符串時(shí),調(diào)用intern方法返回的地址為堆中的地址,對(duì)應(yīng)圖中的0x99。而wechat4本來(lái)地址指向的就是堆中的地址,因此不會(huì)發(fā)生變化。

此時(shí)如果再定義一個(gè)雙引號(hào)賦值的wechat5,如下代碼:

String s2 = "關(guān)注";
String wechat4 = new String(s2 + "公眾號(hào)");
wechat4 = wechat4.intern();

String wechat5 = "關(guān)注公眾號(hào)";
System.out.println(wechat4 == wechat5);

變量wechat5初始化時(shí)發(fā)現(xiàn)字符串常量池中已經(jīng)存在了一個(gè)引用,那么wechat5會(huì)直接指向這個(gè)引用,也就是wechat5和wechat4一樣,都指向內(nèi)存中的String對(duì)象。 JVM字符串常量池及String的intern方法是什么樣的

小結(jié)

上面這個(gè)演示實(shí)例時(shí)需要注意的重點(diǎn)是intern方法返回的引用地址。如果字符串常量池中已經(jīng)存在對(duì)應(yīng)的字符串時(shí),此時(shí)返回的是字符串常量的地址【常量池中存儲(chǔ)的是字符串】,如果字符串常量池中不存在對(duì)應(yīng)的字符串,此時(shí)會(huì)把堆中的引用放在常量池對(duì)應(yīng)的位置【常量池中存儲(chǔ)的是堆中字符串的引用】,此時(shí)intern返回的是堆中字符串對(duì)應(yīng)的引用。

搞清楚了上面的返回邏輯再看最初的代碼:

String s1 = new String("he") + new String("llo");
String s2 = new String("h") + new String("ello");

String s3 = s1.intern();
String s4 = s2.intern();
System.out.println(s1 == s3);
System.out.println(s1 == s4);

其中s1為堆中字符串“hello”的地址;s2為堆中另外一個(gè)“hello”字符串的地址。當(dāng)s1.intern(),常量池中存儲(chǔ)了s1的地址,此時(shí)s1.intern()返回的也是s1的地址,因此s1=s3,都是同一個(gè)地址嘛。

然后執(zhí)行s2.intern(),此時(shí)常量池中已經(jīng)有hello字符串,類(lèi)型為引用且指向s1的地址,執(zhí)行之后返回的便是s1的地址,賦值給s4,因此s1和s4也指向同一個(gè)地址,因此相等。

通過(guò)上面的更深層次的分析,想必大家對(duì)字符串常量、字符串常量池以及intern方法有了更加深刻的理解。

關(guān)于JVM字符串常量池及String的intern方法是什么樣的就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,可以學(xué)到更多知識(shí)。如果覺(jué)得文章不錯(cuò),可以把它分享出去讓更多的人看到。

分享名稱(chēng):JVM字符串常量池及String的intern方法是什么樣的
當(dāng)前網(wǎng)址:http://aaarwkj.com/article24/peihce.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供手機(jī)網(wǎng)站建設(shè)、外貿(mào)建站、網(wǎng)站設(shè)計(jì)、小程序開(kāi)發(fā)、服務(wù)器托管、網(wǎng)頁(yè)設(shè)計(jì)公司

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶(hù)投稿、用戶(hù)轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀(guān)點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話(huà):028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)

成都定制網(wǎng)站網(wǎng)頁(yè)設(shè)計(jì)
成人黄色av在线看| 欧美日韩一区中文字幕| 亚洲精品一区二区三区三州| 国产又黄又粗的视频| 国产精品欧美日韩高清| 亚洲男女内射在线视频| 最新亚洲av熟女播放| 国产激情片午夜福利| 欧美亚洲一区二区三区精品 | 三级黄色片免费久久久| 亚洲永久免费精品一区二区三区| 人妻艳情一区二区三区| 国产综合永久精品日韩鬼片| 亚洲综合日韩欧美一区二区三区| 国产精品无遮挡猛进猛出| 亚洲一区二区三区熟女少妇| 综合久久—本道中文字幕| 亚洲综合色一区二区三区四区 | 蜜桃网站视频免费观看| 97资源在线公开视频| 亚洲黄色片大奶子水多| 每日更新中文字幕粉嫩av| 日韩中文字幕专区在线| 五月婷婷丁香噜噜噜噜| 欧美黄片精品在线观看| 精品蜜臀国产av一区二区| 欧美国产精品中文字幕| 18岁以下禁看视频网站| 日本高清不卡在线观看| 亚洲一区二区视频在线播放| av天堂久久这里只有精品美国| 国产精品日本一区二区| 日日插天天干夜夜操| 色综合色综合蘑菇在线| 成人性生交免大片免费| 亚洲精品一区二区播放| 四虎精品视频在线免费| 国产精品人妻在线av| 91麻豆国产在线视频| 亚洲国产视频中文字幕| 国产一级r内射视频播放|