不同 JDK 的 String.Intern ( ) 的不同之處

最近在讀 《深入理解java虛擬機(jī)》泞坦,總結(jié)一下 String.intern 知識(shí)點(diǎn),引入書中的一個(gè)題目:

    public class RuntimeConstantPoolOOM {
            public static void main(String[] args){
                String str1 = new StringBuilder("計(jì)算機(jī)").append("軟件").toString();
                System.out.println(str1.intern() == str1);

                String str2 = new StringBuilder("ja").append("va").toString();
                System.out.println(str2.intern() == str2);

              }

        }

這段代碼在JDK 1.6中運(yùn)行砖顷,會(huì)得到兩個(gè)false贰锁,而在JDK1.7中運(yùn)行,會(huì)得到一個(gè)true和一個(gè)false滤蝠。產(chǎn)生差異的原因是:在JDK1.6中豌熄,intern()方法會(huì)把首次遇到的字符串實(shí)例復(fù)制到永久代中,返回的也是永久代中這個(gè)字符串實(shí)例的引用物咳,而StringBuildler創(chuàng)建的字符串實(shí)例在Java堆上锣险,所以必然不是一個(gè)引用,將返回false览闰。而JDK1.7中(以及部分其他虛擬機(jī)芯肤,例如JRockit)的intern()實(shí)現(xiàn)不會(huì)再 復(fù)制實(shí)例,只是在常量池中記錄首次出現(xiàn)實(shí)例的引用焕济,因此intern()返回的引用和由StringBuilder創(chuàng)建的字符串實(shí)例是同一個(gè);對(duì)str2比較返回false是因?yàn)椤癹ava”這個(gè)字符串在執(zhí)行StringBuilder.toString()之前已經(jīng)出現(xiàn)過纷妆,字符串常量池中已經(jīng)有它的引用盔几,不符合首次出現(xiàn)的規(guī)則晴弃,而"計(jì)算機(jī)軟件"這個(gè)字符串則是首次出現(xiàn)的,因?yàn)榉祷豻rue;

下面引入幾幅圖對(duì) intern 方法作如下總結(jié):
  • new String 都是在堆上創(chuàng)建字符串對(duì)象逊拍。當(dāng)調(diào)用 intern() 方法時(shí)上鞠,JDK1.6中編譯器會(huì)將字符串添加到常量池中,并返回指向該常量的引用。
image
image
  • 通過字面量賦值創(chuàng)建字符串(如:String str=”twm”)時(shí)芯丧,會(huì)先在常量池中查找是否存在相同的字符串芍阎,若存在,則將棧中的引用直接指向該字符串缨恒;若不存在谴咸,則在常量池中生成一個(gè)字符串球恤,再將棧中的引用指向該字符串具温。
image
  • 常量字符串的“+”操作,編譯階段直接會(huì)合成為一個(gè)字符串世蔗。如string str=”JA”+”VA”萧锉,在編譯階段會(huì)直接合并成語句String str=”JAVA”珊随,于是會(huì)去常量池中查找是否存在”JAVA”,從而進(jìn)行創(chuàng)建或引用。
  • 對(duì)于final字段,編譯期直接進(jìn)行了常量替換(而對(duì)于非final字段則是在運(yùn)行期進(jìn)行賦值處理的)叶洞。
    final String str1 = ”ja” ;

    final String str2 = ”va” ;

    String str3 = str1+str2 ;

在編譯時(shí)鲫凶,直接替換成了 String str3 = ”ja” + ”va”,根據(jù)第三條規(guī)則衩辟,再次替換成 String str3=”JAVA” 螟炫。

  • 常量字符串和變量拼接時(shí)(如:String str3 = baseStr + “01” ;)會(huì)調(diào)用 stringBuilder.append() 在堆上創(chuàng)建新的對(duì)象。
  • JDK 1.7 后惭婿,intern 方法還是會(huì)先去查詢常量池中是否有已經(jīng)存在不恭,如果存在,則返回常量池中的引用财饥,這一點(diǎn)與之前沒有區(qū)別换吧,區(qū)別在于,如果在常量池找不到對(duì)應(yīng)的字符串钥星,則不會(huì)再將字符串拷貝到常量池沾瓦,而只是在常量池中生成一個(gè)對(duì)原字符串的引用。簡單的說谦炒,就是往常量池放的東西變了:原來在常量池中找不到時(shí)贯莺,復(fù)制一個(gè)副本放到常量池,1.7后則是將在堆上的地址引用復(fù)制到常量池宁改。

另外參考 關(guān)于String.intern()和new StringBuilder("").append("").toString();

先運(yùn)行這個(gè)代碼 ①

    String str3 = new StringBuilder("ni").append("hao").toString();

    System.out.println(str3==str3.intern());

通過上面的解釋缕探,運(yùn)行結(jié)果為true.

在運(yùn)行這個(gè)代碼 ②

    String str3 = new StringBuilder("nihao").toString();

    System.out.println(str3==str3.intern());

其結(jié)果是什么 ? 應(yīng)該還是 true 吧 ,畢竟通過上一個(gè)運(yùn)行結(jié)果可以知道 "nihao" 這個(gè)字符串常量沒有被預(yù)先加載到常量池中 还蹲。
但是運(yùn)行結(jié)果卻是 false .

解釋如下 :上面的 ① 代碼等價(jià)于下面的代碼

    String a = "ni";

    String b = "hao";
    
    String str3 = new StringBuilder(a).append(b).toString();
    
    System.out.println(str3==str3.intern());

很容易分析出 :

“nihao” 最先創(chuàng)建在堆中 str3.intern() 然后緩存在字符串常連池中 運(yùn)行結(jié)果為 true .

代碼 ② 等價(jià)于

    String a = "nihao";

    String str3 = new StringBuilder(a).toString();
    
    System.out.println(str3==str3.intern());

很容易分析出:

“nihao” 最先創(chuàng)建在常量池中, 運(yùn)行結(jié)果為false.

new String()和new StringBuilder()同樣的原理爹耗,由此對(duì)于一道 經(jīng)典的Java面試題

在Java中,new String("hello")這樣的創(chuàng)建方式谜喊,到底創(chuàng)建了幾個(gè)String對(duì)象 ?

題目下答案眾說紛紜潭兽,有說1的有說2的,我覺得各有各的道理斗遏,如果常量池中有“hello”的字符串山卦,當(dāng)然只會(huì)創(chuàng)建1個(gè),如果沒有則會(huì)創(chuàng)建2個(gè)诵次;

new String ("hello")相當(dāng)于如下代碼:

    String temp = "hello";  // 在常量池中

    String str = new String(temp); // 在堆上
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末账蓉,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子逾一,更是在濱河造成了極大的恐慌铸本,老刑警劉巖,帶你破解...
    沈念sama閱讀 210,978評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件嬉荆,死亡現(xiàn)場離奇詭異归敬,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,954評(píng)論 2 384
  • 文/潘曉璐 我一進(jìn)店門汪茧,熙熙樓的掌柜王于貴愁眉苦臉地迎上來椅亚,“玉大人,你說我怎么就攤上這事舱污⊙教颍” “怎么了?”我有些...
    開封第一講書人閱讀 156,623評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵扩灯,是天一觀的道長媚赖。 經(jīng)常有香客問我,道長珠插,這世上最難降的妖魔是什么惧磺? 我笑而不...
    開封第一講書人閱讀 56,324評(píng)論 1 282
  • 正文 為了忘掉前任,我火速辦了婚禮捻撑,結(jié)果婚禮上磨隘,老公的妹妹穿的比我還像新娘。我一直安慰自己顾患,他們只是感情好番捂,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,390評(píng)論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著江解,像睡著了一般设预。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上犁河,一...
    開封第一講書人閱讀 49,741評(píng)論 1 289
  • 那天鳖枕,我揣著相機(jī)與錄音,去河邊找鬼呼股。 笑死耕魄,一個(gè)胖子當(dāng)著我的面吹牛画恰,可吹牛的內(nèi)容都是我干的彭谁。 我是一名探鬼主播,決...
    沈念sama閱讀 38,892評(píng)論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼允扇,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼缠局!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起考润,我...
    開封第一講書人閱讀 37,655評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤狭园,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后糊治,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體唱矛,經(jīng)...
    沈念sama閱讀 44,104評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,451評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了绎谦。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片管闷。...
    茶點(diǎn)故事閱讀 38,569評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖窃肠,靈堂內(nèi)的尸體忽然破棺而出包个,到底是詐尸還是另有隱情,我是刑警寧澤冤留,帶...
    沈念sama閱讀 34,254評(píng)論 4 328
  • 正文 年R本政府宣布碧囊,位于F島的核電站,受9級(jí)特大地震影響纤怒,放射性物質(zhì)發(fā)生泄漏糯而。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,834評(píng)論 3 312
  • 文/蒙蒙 一泊窘、第九天 我趴在偏房一處隱蔽的房頂上張望歧蒋。 院中可真熱鬧,春花似錦州既、人聲如沸谜洽。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,725評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽阐虚。三九已至,卻和暖如春蚌卤,著一層夾襖步出監(jiān)牢的瞬間实束,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,950評(píng)論 1 264
  • 我被黑心中介騙來泰國打工逊彭, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留咸灿,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,260評(píng)論 2 360
  • 正文 我出身青樓侮叮,卻偏偏與公主長得像避矢,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子囊榜,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,446評(píng)論 2 348