從字節(jié)碼(ByteCode)角度理解String的連接

首先來(lái)看一道題。

題目描述

問(wèn)下面兩種賦值方式有何區(qū)別譬巫?

public class Demo {
    public static void main(String[] args) {

        String s = "1" + "2" + "3";

        String s1 = "1";
        String s2 = s1 + "2";
        String s3 = s2 + "3";

        System.out.println(s);
        System.out.println(s3);
    }
}


分析解答

從表面其實(shí)看不出什么咖楣,我們可以通過(guò)Class文件反編譯成的字節(jié)碼(Byte Code)來(lái)分析。

如果你在使用IDEA芦昔,請(qǐng)先在IDEA中安裝ASMified Bytecode Online插件诱贿,安裝詳細(xì)教程->推薦幾個(gè)可以提高程序員生存技能的效率軟件,如果是其他集成環(huán)境咕缎,請(qǐng)自行Google安裝插件教程珠十。

ASMified Bytecode Online插件作用:用于將Class文件反編譯成字節(jié)碼(Byte Code)形式。將上面代碼在IDEA中運(yùn)行后凭豪,生成的字節(jié)碼(Byte Code)如下圖所示:

...
public static void main(String[] a) {
    ldc "123"
    //astore 1
    ldc "1"
    //astore 2
    _new 'java/lang/StringBuilder'
    //dup
    //INVOKESPECIAL java/lang/StringBuilder.<init> ()V
    //aload 2
    INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
    ldc "2"
    INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
    INVOKEVIRTUAL java/lang/StringBuilder.toString ()Ljava/lang/String;
    //astore 3
    _new 'java/lang/StringBuilder'
    //dup
    //INVOKESPECIAL java/lang/StringBuilder.<init> ()V
    //aload 3
    INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
    ldc "3"
    INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
    INVOKEVIRTUAL java/lang/StringBuilder.toString ()Ljava/lang/String;
    ....
}

看不懂焙蹭,沒(méi)關(guān)系!你只需要知道幾個(gè)指令就能理解了嫂伞。根據(jù)《深入理解Java虛擬機(jī)(第二版)》---周志明著的第六章知識(shí)可知:

  • ldc指令:將一個(gè)常量加載到操作數(shù)棧孔厉。
  • _new指令:實(shí)例化對(duì)象
  • invokevirtual指令:用于調(diào)用對(duì)象的實(shí)例方法,根據(jù)對(duì)象的實(shí)際類型進(jìn)行分派(虛方法分派)帖努,這也是Java語(yǔ)言中最常見(jiàn)的方法分派方式撰豺。

我們根據(jù)字節(jié)碼順序來(lái)看:

// "1"+"2"+"3"被JVM轉(zhuǎn)換成了字符串常量"123"存儲(chǔ)到操作數(shù)棧
String s = "1" + "2" + "3";

跳過(guò)astore、dup等指令(不是本節(jié)重點(diǎn))

/**
 * JVM將"1"存儲(chǔ)到操作數(shù)棧
 * JVM用_new指令實(shí)例化一個(gè)StringBuilder對(duì)象,調(diào)用append()方法連接"1"
 * JVM將"2"存儲(chǔ)到操作數(shù)棧
 * 調(diào)用append()方法連接"2"
 * 調(diào)用toString()轉(zhuǎn)換成String類型
 * JVM_new指令再實(shí)例化一個(gè)StringBuilder對(duì)象拼余,調(diào)用append()方法連接"12"
 * JVM將"3"存儲(chǔ)到操作數(shù)棧
 * 調(diào)用append()方法連接"3"
 * 調(diào)用toString()轉(zhuǎn)換成String類型
 * */
String s1 = "1";
String s2 = s1 + "2";
String s3 = s2 + "3";

當(dāng)時(shí)用使用+操作符連接字符串時(shí)污桦,為什么兩者有無(wú)字符串對(duì)象就有區(qū)別呢?

是因?yàn)槿绻怀霈F(xiàn)字符串引用匙监,字符串常量的值在編譯期時(shí)就可以確定下來(lái)凡橱,所以不會(huì)使用到StringBuilder;如果出現(xiàn)字符串引用亭姥,JVM不能將字符串引用和字符串常量直接連接稼钩,所以將在運(yùn)行期間動(dòng)態(tài)生成StringBuilder對(duì)象,讓它去實(shí)現(xiàn)連接致份。

說(shuō)了StringBuilder变抽,就不能不提StringBuffer础拨,兩者最大的區(qū)別是氮块,前者線程不安全的,后者是線程安全的诡宗。不能一看是線程不安全就覺(jué)得不好滔蝉,其實(shí)線程不安全比線程安全效率高,再者塔沃,因?yàn)槲覀儗?xiě)的一些代碼不用線程安全這樣多此一舉蝠引。

特別注意!在循環(huán)中連接字符串時(shí),最好不要出現(xiàn)字符串引用螃概,因?yàn)槊看窝h(huán)都會(huì)新建StringBuilder矫夯,即使Java有垃圾回收機(jī)制,這樣也很浪費(fèi)資源吊洼。這時(shí)候就可以用StringBuilder來(lái)連接字符串训貌。

public class Demo {
    public static void main(String[] args) {
        
        //我們這樣寫(xiě)
        StringBuilder builder = new StringBuilder();
        for (int i = 1; i < 10; i++) {
            builder.append(i);
        }
        System.out.println(builder.toString());

        //而不是這樣寫(xiě)
        String s = "";
        for (int i = 1; i < 10; i++) {
            s = s + i;
        }
        System.out.println(s);

    }
}

總結(jié)

如果此博文謬誤,還望各位路過(guò)的朋友指正!

參考網(wǎng)址

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末冒窍,一起剝皮案震驚了整個(gè)濱河市递沪,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌综液,老刑警劉巖款慨,帶你破解...
    沈念sama閱讀 218,036評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異谬莹,居然都是意外死亡檩奠,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,046評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門附帽,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)笆凌,“玉大人,你說(shuō)我怎么就攤上這事士葫∑蚨” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,411評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵慢显,是天一觀的道長(zhǎng)爪模。 經(jīng)常有香客問(wèn)我,道長(zhǎng)荚藻,這世上最難降的妖魔是什么屋灌? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,622評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮应狱,結(jié)果婚禮上共郭,老公的妹妹穿的比我還像新娘。我一直安慰自己疾呻,他們只是感情好除嘹,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,661評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著岸蜗,像睡著了一般尉咕。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上璃岳,一...
    開(kāi)封第一講書(shū)人閱讀 51,521評(píng)論 1 304
  • 那天年缎,我揣著相機(jī)與錄音悔捶,去河邊找鬼。 笑死单芜,一個(gè)胖子當(dāng)著我的面吹牛蜕该,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播洲鸠,決...
    沈念sama閱讀 40,288評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼蛇损,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了坛怪?” 一聲冷哼從身側(cè)響起淤齐,我...
    開(kāi)封第一講書(shū)人閱讀 39,200評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎袜匿,沒(méi)想到半個(gè)月后更啄,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,644評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡居灯,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,837評(píng)論 3 336
  • 正文 我和宋清朗相戀三年祭务,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片怪嫌。...
    茶點(diǎn)故事閱讀 39,953評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡义锥,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出岩灭,到底是詐尸還是另有隱情拌倍,我是刑警寧澤,帶...
    沈念sama閱讀 35,673評(píng)論 5 346
  • 正文 年R本政府宣布噪径,位于F島的核電站柱恤,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏找爱。R本人自食惡果不足惜梗顺,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,281評(píng)論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望车摄。 院中可真熱鬧寺谤,春花似錦、人聲如沸吮播。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,889評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)薄料。三九已至敞贡,卻和暖如春泵琳,著一層夾襖步出監(jiān)牢的瞬間摄职,已是汗流浹背誊役。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,011評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留谷市,地道東北人蛔垢。 一個(gè)月前我還...
    沈念sama閱讀 48,119評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像迫悠,于是被迫代替她去往敵國(guó)和親鹏漆。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,901評(píng)論 2 355

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