JAVA工程師常見面試題(四):字符串面試題深入解析

問題

以下字符串對比的結(jié)果是什么?

String s1 = "ni" + "hao";
String s2 = "ni";
s2 += "hao";
String s3 = "nihao";
System.out.println(s1 == s2);
System.out.println(s1 == s3);
System.out.println(s2 == s3);

答:false true false

我們來看編譯器編譯之后的代碼:

        String s1 = "nihao";
        String s2 = "ni";
        s2 = s2 + "hao";
        String s3 = "nihao";
        System.out.println(s1 == s2);
        System.out.println(s1 == s3);
        System.out.println(s2 == s3);

很顯然s1在經(jīng)過編譯器優(yōu)化之后独悴,他們的內(nèi)容相同,都是"nihao"逾苫。接下來我們理解一下對于String來說==到底比較的是什么声怔。

JAVA中的==

java中的數(shù)據(jù)類型堂鲤,可分為兩類:
1.基本數(shù)據(jù)類型锤窑,也稱原始數(shù)據(jù)類型甚淡。byte,short,char,int,long,float,double,boolean 他們之間的比較演怎,應用雙等號(==),比較的是他們的值匕争。
2.復合數(shù)據(jù)類型(類)
當他們用(==)進行比較的時候,比較的是他們在內(nèi)存中的存放地址爷耀,所以甘桑,除非是同一個new出來的對象,他們的比較后的結(jié)果為true歹叮,否則比較后結(jié)果為false跑杭。
那么s1和s3是否指向內(nèi)存中同一個對象呢?

字符串常量池

字符串的分配咆耿,和其他的對象分配一樣德谅,耗費高昂的時間與空間代價,作為最基礎(chǔ)的數(shù)據(jù)類型萨螺,大量頻繁的創(chuàng)建字符串窄做,極大程度地影響程序的性能。JVM為了提高性能和減少內(nèi)存開銷慰技,在實例化字符串常量的時候進行了一些優(yōu)化為字符串開辟一個字符串常量池椭盏,類似于緩存區(qū)。創(chuàng)建字符串常量時惹盼,首先檢查字符串常量池是否存在該字符串:存在該字符串庸汗,返回引用實例;不存在手报,實例化該字符串并放入池中蚯舱。

常量池的實現(xiàn)

字符串常量池則存在于方法區(qū)改化,可以被所有線程共享。.jdk1.6 方法區(qū)放在永久代(java堆的一部分)枉昏,jdk1.7以后特別將字符串常量池移動到了的堆內(nèi)存中(使用參數(shù)-XX:PermSize 和-XX:MaxPermSize指定大谐赂亍)。所以導致string的intern方法因為以上變化在不同版本會有不同表現(xiàn)兄裂。

以下代碼在內(nèi)存中存放的結(jié)構(gòu)如圖所示:

String str1 = “abc”;
String str2 = “abc”;
String str3 = “abc”;
String str4 = new String(“abc”);
String str5 = new String(“abc”);
1353903-20180906112918874-831560949.png

那么String str4 = new String(“abc”) 創(chuàng)建多少個對象句旱?首先在常量池中查找是否有“abc”對象有則返回對應的引用實例,如果沒有則在常量池中創(chuàng)建對應的實例對象晰奖,同時在堆中 new 一個 String("abc") 對象谈撒,將對象地址賦值給str4,創(chuàng)建一個引用。

String的intern方法

從上文中介紹可以知道匾南,以下代碼

String str1 = “abc”;
String str4 = new String(“abc”);

其中str1 == str4判斷會返回false啃匿,因為str1指向常量池中的對象,而str4指向堆中的對象蛆楞。但是我們可以使用intern方法溯乒,重新獲取一個常量池里的對象。

String str1 = “abc”;
String str4 = new String(“abc”).intern();

這樣的話str1 == str4判斷就會返回true了豹爹。如果在循環(huán)中多次要使用到String裆悄,可以直接從常量池中獲取到這個字符串使用,這樣就可以大大減少堆內(nèi)存上的開銷臂聋。

查看常量池

使用Idea中的JclassLib插件查看常量池光稼,我們依然以如下代碼為例:

String s1 = "ni" + "hao";
String s2 = "ni";
s2 += "hao";
String s3 = "nihao";
System.out.println(s1 == s2);
System.out.println(s1 == s3);
System.out.println(s2 == s3);
image.png

聲明s1之后,常量池中創(chuàng)建了123的字符串孩等。


image.png

聲明s2之后钟哥,常量池中創(chuàng)建了12的字符串。
所以這兩者在常量池中的對象是不同的瞎访,但這個就是我們最終的結(jié)論嗎?顯然不是吁恍。

分析字節(jié)碼

我們用jClassLib分析class文件的字節(jié)碼:


從上圖中可以看到s2 += "hao";這句代碼扒秸,其實在JVM中運行時,創(chuàng)建了一個StringBuilder對象冀瓦,然后使用append方法添加了s2的字符串伴奥,再添加"hao"字符串,最后調(diào)用toString的方法生成最終結(jié)果翼闽。所以s2的字符串是使用StringBuilder創(chuàng)建的新對象拾徙,和常量池中的"123"自然就沒有關(guān)系了。

總結(jié):

對于s1來說感局,編譯器將其優(yōu)化為s1="123",在常量池中創(chuàng)建對象尼啡。
對于s2來說暂衡,創(chuàng)建"12"的常量池對象,同時使用StringBuilder創(chuàng)建新對象崖瞭。
對于s3來說狂巢,常量池中已有"123",直接指向常量池中的對象。
所以結(jié)果為false true false书聚。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末唧领,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子雌续,更是在濱河造成了極大的恐慌斩个,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,968評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件驯杜,死亡現(xiàn)場離奇詭異受啥,居然都是意外死亡,警方通過查閱死者的電腦和手機艇肴,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評論 2 382
  • 文/潘曉璐 我一進店門腔呜,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人再悼,你說我怎么就攤上這事核畴。” “怎么了冲九?”我有些...
    開封第一講書人閱讀 153,220評論 0 344
  • 文/不壞的土叔 我叫張陵谤草,是天一觀的道長。 經(jīng)常有香客問我莺奸,道長丑孩,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,416評論 1 279
  • 正文 為了忘掉前任灭贷,我火速辦了婚禮温学,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘甚疟。我一直安慰自己仗岖,他們只是感情好,可當我...
    茶點故事閱讀 64,425評論 5 374
  • 文/花漫 我一把揭開白布览妖。 她就那樣靜靜地躺著轧拄,像睡著了一般。 火紅的嫁衣襯著肌膚如雪讽膏。 梳的紋絲不亂的頭發(fā)上檩电,一...
    開封第一講書人閱讀 49,144評論 1 285
  • 那天,我揣著相機與錄音,去河邊找鬼俐末。 笑死料按,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的鹅搪。 我是一名探鬼主播站绪,決...
    沈念sama閱讀 38,432評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼丽柿!你這毒婦竟也來了恢准?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,088評論 0 261
  • 序言:老撾萬榮一對情侶失蹤甫题,失蹤者是張志新(化名)和其女友劉穎馁筐,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體坠非,經(jīng)...
    沈念sama閱讀 43,586評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡敏沉,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,028評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了炎码。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片盟迟。...
    茶點故事閱讀 38,137評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖潦闲,靈堂內(nèi)的尸體忽然破棺而出攒菠,到底是詐尸還是另有隱情,我是刑警寧澤歉闰,帶...
    沈念sama閱讀 33,783評論 4 324
  • 正文 年R本政府宣布辖众,位于F島的核電站,受9級特大地震影響和敬,放射性物質(zhì)發(fā)生泄漏凹炸。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,343評論 3 307
  • 文/蒙蒙 一昼弟、第九天 我趴在偏房一處隱蔽的房頂上張望啤它。 院中可真熱鬧,春花似錦舱痘、人聲如沸蚕键。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至笆怠,卻和暖如春铝耻,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評論 1 262
  • 我被黑心中介騙來泰國打工瓢捉, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留频丘,地道東北人。 一個月前我還...
    沈念sama閱讀 45,595評論 2 355
  • 正文 我出身青樓泡态,卻偏偏與公主長得像搂漠,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子某弦,可洞房花燭夜當晚...
    茶點故事閱讀 42,901評論 2 345

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