不能用 + 拼接字符串? 这次我要吊打面试官!
好久沒(méi)維護(hù)《吊打面試官》系列了,今天再來(lái)一篇,這次真的要吊打了,哈哈!(看往期吊打系列請(qǐng)?jiān)诤笈_(tái)回復(fù):吊打,我會(huì)陸續(xù)更新……)
我們做 Java 程序員以來(lái),不管是工作當(dāng)中,還是面試過(guò)程中,都知道:字符串拼接不能用 String,要用?StringBuilder?或者是?StringBuffer,以至于它們都被濫用了。
StringBuilder、StringBuffer 簡(jiǎn)稱:SB,下文統(tǒng)一用?SB?代替。
SB它們都是可變的字符串,它們之間的區(qū)別也是 Java 初中級(jí)面試戰(zhàn)場(chǎng)上出現(xiàn)幾率十分高的一道題,上場(chǎng)率沒(méi)有 90% 也有 80% 吧。
這兩個(gè)的具體區(qū)別請(qǐng)看這篇文章:StringBuffer 和 StringBuilder 的 3 個(gè)區(qū)別。
我們反過(guò)來(lái)想下,String真的是不可變的么?不一定,看下這篇:Java 中的 String 真的是不可變的嗎?
當(dāng)然,本文不是討論字符串可變與不可變的問(wèn)題,而是討論:字符串拼接一定要用?SB?嗎?為什么不能用?+??能不能用?+??什么時(shí)候可以用?+??
為什么不能用 + 號(hào)拼接字符串?我不服,接下來(lái)我要吊打面試官!
什么時(shí)候不能用 `+`
通過(guò)多個(gè)表達(dá)式完成一個(gè)字符串拼接操作。
private?void?test1()?{String?www?=?"www.";String?str?=?www;str?+=?"javastack.";str?+=?"com"; }字節(jié)碼如下:
//?access?flags?0xA private?static?test2()V L0 LINENUMBER?14?L0 LDC?"www." ASTORE?0 L1 LINENUMBER?15?L1 ALOAD?0 ASTORE?1 L2 LINENUMBER?16?L2 NEW?java/lang/StringBuilder DUP INVOKESPECIAL?java/lang/StringBuilder.<init>?()V ALOAD?1 INVOKEVIRTUAL?java/lang/StringBuilder.append?(Ljava/lang/String;)Ljava/lang/StringBuilder; LDC?"javastack." INVOKEVIRTUAL?java/lang/StringBuilder.append?(Ljava/lang/String;)Ljava/lang/StringBuilder; INVOKEVIRTUAL?java/lang/StringBuilder.toString?()Ljava/lang/String; ASTORE?1 L3 LINENUMBER?17?L3 NEW?java/lang/StringBuilder DUP INVOKESPECIAL?java/lang/StringBuilder.<init>?()V ALOAD?1 INVOKEVIRTUAL?java/lang/StringBuilder.append?(Ljava/lang/String;)Ljava/lang/StringBuilder; LDC?"com" INVOKEVIRTUAL?java/lang/StringBuilder.append?(Ljava/lang/String;)Ljava/lang/StringBuilder; INVOKEVIRTUAL?java/lang/StringBuilder.toString?()Ljava/lang/String; ASTORE?1 L4 LINENUMBER?18?L4 RETURN L5 LOCALVARIABLE?www?Ljava/lang/String;?L1?L5?0 LOCALVARIABLE?str?Ljava/lang/String;?L2?L5?1 MAXSTACK?=?2 MAXLOCALS?=?2不會(huì)查看字節(jié)碼的,看這里:3種騷操作,教你查看 Java 字節(jié)碼,看這一篇就會(huì)了。
觀察下,NEW java/lang/StringBuilder?出現(xiàn)了兩次,是因?yàn)槲覀冊(cè)诖a中拼接了兩次,也就是說(shuō)每一次拼接操作都會(huì)創(chuàng)建一次?StringBuilder。
如果我們是在一個(gè)循環(huán)中進(jìn)行字符串拼接,那是不是一次拼接就要?jiǎng)?chuàng)建一個(gè)?StringBuilder?
wtf……這哪能接受!頻繁創(chuàng)建對(duì)象是有性能開(kāi)銷的,這也是為什么我們常說(shuō)的字符串不能用?+?拼接,而要用那兩個(gè)?SB??拼接了。
?
什么時(shí)候可以用 `+`
直接將三個(gè)字面量的字符串拼接成一個(gè)字符串。
private?static?void?test2()?{String?str?=?"www."?+?"javastack."?+?"com"; }字節(jié)碼如下:
//?access?flags?0x2 private?test2()V L0 LINENUMBER?13?L0 LDC?"www.javastack.com" ASTORE?1 L1 LINENUMBER?14?L1 RETURN L2 LOCALVARIABLE?this?Lcom/test/jdk/TestSB;?L0?L2?0 LOCALVARIABLE?str?Ljava/lang/String;?L1?L2?1 MAXSTACK?=?1 MAXLOCALS?=?2從字節(jié)碼看出,沒(méi)有任何創(chuàng)建?StringBuilder?的指令,直接從常量池進(jìn)行取出一個(gè)完整的字符串:www.javastack.com。很明顯,這是 Java 編譯器對(duì)代碼進(jìn)行了優(yōu)化。
所以,通過(guò)這個(gè)示例告訴你,在這種情況下是可以用?+?號(hào)進(jìn)行字符串拼接的。
這個(gè)示例可以演變成我們實(shí)際工作當(dāng)中的某個(gè) SQL 語(yǔ)句拼接的案例,如:
String?sql?=?"select?name,?sex,?age,?address"+?"from?t_user"+?"where?age?>?18";別說(shuō)這樣不行,這樣是行的。
但你要是換成這樣就不行了:
String?sql?=?"select?name,?sex,?age,?address"; sql?+=?"from?t_user"; sql?+=?"where?age?>?18";這樣又回到創(chuàng)建多個(gè)?StringBuilder?的時(shí)候了。
也就是說(shuō),在一個(gè)表達(dá)式中完成字符串拼接是可以用?+?號(hào)完成的,因?yàn)榫幾g器已經(jīng)做了優(yōu)化。
小結(jié)一下
你只需要記住這兩點(diǎn):
1、在循環(huán)和多個(gè)表達(dá)式中不能?+,頻繁創(chuàng)建?SB?性能影響;
2、在單個(gè)表達(dá)式中可以用?+,編譯器直接做了優(yōu)化;
老鐵們,都搞清楚了?
這個(gè)觀點(diǎn)有沒(méi)有被誤解很久?
下次面試,把這篇內(nèi)容亮出來(lái),吊打面試官,沒(méi)問(wèn)題的。
有收獲的朋友一定要點(diǎn)個(gè)在看,這樣我寫(xiě)原創(chuàng)更帶勁了,謝了,老鐵們。
總結(jié)
以上是生活随笔為你收集整理的不能用 + 拼接字符串? 这次我要吊打面试官!的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: StringBuffer 和 Strin
- 下一篇: 女儿问了我一个问题:什么是抽象?