Java字符串“+”你真的明白嗎迅矛?

Java對字符串操作做了許多的優(yōu)化,使用符號“+”來作為字符串拼接操作就是其中之一潜叛。

今天來摳一下這個東西的細節(jié)秽褒。

對于大部分Java開發(fā)來說,都知道Java會使用StringBuilder來優(yōu)化字符串拼接操作威兜。這種優(yōu)化的一個極為重要的出發(fā)點就是销斟,String在Java里面是一個不可變的對象,所謂的字符串拼接不過是用被拼接字符串的內(nèi)容來創(chuàng)建一個新的字符串椒舵。

如果在Java沒有優(yōu)化的情況下蚂踊,字符串拼接就變成不斷創(chuàng)建新的String對象,每一個創(chuàng)建的對象都是一次拼接的結(jié)果笔宿。

StringBuilder可以減少這種開銷犁钟。StringBuilder的原理非常接近ArrayList棱诱,即內(nèi)部維持一個數(shù)組,在容量不足的情況下擴容涝动。因此在使用StringBuilder的情況下迈勋,可以有效減少創(chuàng)建對象的次數(shù)。

那么問題來了:

  1. 是所有的字符串拼接都會被優(yōu)化嗎醋粟?
  2. 編譯器做這種優(yōu)化的時候靡菇,是如何確保線程安全的?

所有的字符串拼接都會被優(yōu)化嗎米愿?

答案是YES厦凤,但是并不是所有的字符串拼接都會被同種方式——即使用StringBuilder——所優(yōu)化。

這里存在一種更加強大的優(yōu)化:編譯器如果在編譯期間就能確定字符串拼接的結(jié)果育苟,那么編譯器會將字符串拼接操作去掉较鼓,改為直接使用拼接后的結(jié)果——即編譯器自身完成這個拼接操作。

實際上宙搬,這是編譯器優(yōu)化的一小部分工作笨腥。除了字符串拼接以外,還有數(shù)值計算勇垛,也會有類似的優(yōu)化脖母。換句話來說,在現(xiàn)代編譯器里面闲孤,編譯器會努力把計算提前做完——前提是它能夠確切結(jié)算出來結(jié)果谆级。與之類似的一個東西是Java的類加載過程會完成部分方法解析,即將方法調(diào)用指向真正的方法讼积。這些體現(xiàn)的核心理念就是能在運行前完成的肥照,就做完。

如:

字節(jié)碼是:

也就是它實際上是直接使用hello world作為打印參數(shù)的值勤众。

這里有意思的是舆绎,它在0,2们颜,3吕朵,5的四條指令,實際上是可以忽略的窥突。不過這并不是字符串拼接造成的努溃,實際上是編譯整體不夠智能造成的。編譯器其實在這個時候并沒有斷定后面除了用于字符串拼接以外阻问,ab兩個局部變量沒有再使用過梧税。所以編譯器只能非常保守的繼續(xù)保留著四條指令。

這四條指令在JIT階段有極大的可能會被優(yōu)化掉。不過那都是在運行期的時候了第队。

另外哮塞,是否注意到圖中我將兩個局部變量都聲明成了final了。那是因為斥铺,只有聲明成final彻桃,編譯器才能確定該變量的值,并且可以肯定這個變量的值在拼接操作并未被修改過晾蜘。

如果沒有final關(guān)鍵字邻眷,那么會變成:

也就是使用StringBuiler

這里我要額外討論一個所謂的事實final變量剔交。在Java里面肆饶,最開始使用內(nèi)部匿名類的時候,內(nèi)部匿名類要使用外部變量岖常,那么只能將該外部變量聲明成final驯镊。

否則編譯器會報錯。

直到后來(忘了是哪個版本竭鞍,好像是Java8引入lambda表達式的時候)板惑,如果編譯器確定你這個變量中途并未被修改過,那么即便不聲明成final都可以在內(nèi)部匿名類使用偎快。

這就是所謂的事實final變量冯乘。這個名詞是我杜撰的,專業(yè)的說法不知道叫什么晒夹。

所以理論上裆馒,編譯器是完全可以斷定在這個過程中字符串變量有沒有被修改過,而后執(zhí)行這種優(yōu)化的丐怯。很可惜喷好,編譯器并沒有利用這個信息。這是我一直覺得稍微有點遺憾的地方读跷。

StringBuilder的優(yōu)化是如何保證線程安全的梗搅?

這是一個看起來沒什么營養(yǎng)的問題,一思考又覺得很有營養(yǎng)的問題效览,考慮清楚之后終于確定的確沒什么營養(yǎng)的問題些膨。

答案是,其實它不保證線程安全钦铺,它只是保證和不用StringBuilder優(yōu)化時候的語義一致。這就是指肢预,如果不是用StringBuiler的地方線程不安全矛洞,那么使用StringBuilder優(yōu)化也不安全。

首先,大部分優(yōu)化是安全的沼本,這種線程安全的第一條保證是:String是不可變類型噩峦。這個無需多說,稍微思考一下就知道的抽兆。

再深入一點的話识补,如前面的例子,因為字符串只出現(xiàn)在方法里面辫红,是作為方法的局部變量出現(xiàn)的凭涂,所以天然是線程安全的。

那么贴妻,如果我的代碼是這樣的呢切油?

這是一個初看起來會線程安全的代碼,實際上卻并沒有的代碼名惩。

先來分析staticC澎胡。staticC是在類初始化的時候完成計算的。JVM的類加載機制可以確保娩鹉,對于一個類加載器來說攻谁,staticC那句代碼,只會被一個線程執(zhí)行弯予。在完成類初始化完成之前戚宦,staticAstaticB是無法被修改的。所以這個可以保證是線程安全的熙涤。

而變量c就要復雜一點了阁苞,理論上,c會在調(diào)用構(gòu)造初始化方法之前完成初始化祠挫。如果從字節(jié)碼的角度來解釋那槽,就是c會在構(gòu)造方法里面的任何代碼執(zhí)行之前完成。

然而創(chuàng)建對象等舔,在JVM層面上并不是一個原子步驟骚灸,它大概是有兩步:

  1. new指令執(zhí)行,大體上可以理解為分配內(nèi)存慌植;
  2. 調(diào)用初始化方法<init>甚牲;

所以在JIT的情況下,可能第一步執(zhí)行完之后蝶柿,引用就被外部獲取了丈钙,這個時候他們就可能并發(fā)修改變量a或者b的值:

  1. new指令執(zhí)行,大體上可以理解為分配內(nèi)存交汤;
  2. a或者b的值被修改---JIT情況下雏赦;
  3. 調(diào)用初始化方法<init>

所以我才說,這種優(yōu)化只保證和沒有優(yōu)化的語義一致星岗。和線程安全沒什么關(guān)系填大。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市俏橘,隨后出現(xiàn)的幾起案子允华,更是在濱河造成了極大的恐慌,老刑警劉巖寥掐,帶你破解...
    沈念sama閱讀 219,539評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件靴寂,死亡現(xiàn)場離奇詭異,居然都是意外死亡曹仗,警方通過查閱死者的電腦和手機榨汤,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,594評論 3 396
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來怎茫,“玉大人收壕,你說我怎么就攤上這事」旄颍” “怎么了蜜宪?”我有些...
    開封第一講書人閱讀 165,871評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長祥山。 經(jīng)常有香客問我圃验,道長,這世上最難降的妖魔是什么缝呕? 我笑而不...
    開封第一講書人閱讀 58,963評論 1 295
  • 正文 為了忘掉前任澳窑,我火速辦了婚禮,結(jié)果婚禮上供常,老公的妹妹穿的比我還像新娘摊聋。我一直安慰自己,他們只是感情好栈暇,可當我...
    茶點故事閱讀 67,984評論 6 393
  • 文/花漫 我一把揭開白布麻裁。 她就那樣靜靜地躺著,像睡著了一般源祈。 火紅的嫁衣襯著肌膚如雪煎源。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,763評論 1 307
  • 那天香缺,我揣著相機與錄音手销,去河邊找鬼。 笑死图张,一個胖子當著我的面吹牛原献,可吹牛的內(nèi)容都是我干的馏慨。 我是一名探鬼主播,決...
    沈念sama閱讀 40,468評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼姑隅,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了倔撞?” 一聲冷哼從身側(cè)響起讲仰,我...
    開封第一講書人閱讀 39,357評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎痪蝇,沒想到半個月后鄙陡,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,850評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡躏啰,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,002評論 3 338
  • 正文 我和宋清朗相戀三年趁矾,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片给僵。...
    茶點故事閱讀 40,144評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡毫捣,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出帝际,到底是詐尸還是另有隱情蔓同,我是刑警寧澤,帶...
    沈念sama閱讀 35,823評論 5 346
  • 正文 年R本政府宣布蹲诀,位于F島的核電站斑粱,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏脯爪。R本人自食惡果不足惜则北,卻給世界環(huán)境...
    茶點故事閱讀 41,483評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望痕慢。 院中可真熱鬧尚揣,春花似錦、人聲如沸守屉。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,026評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽拇泛。三九已至滨巴,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間俺叭,已是汗流浹背恭取。 一陣腳步聲響...
    開封第一講書人閱讀 33,150評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留熄守,地道東北人蜈垮。 一個月前我還...
    沈念sama閱讀 48,415評論 3 373
  • 正文 我出身青樓耗跛,卻偏偏與公主長得像,于是被迫代替她去往敵國和親攒发。 傳聞我的和親對象是個殘疾皇子调塌,可洞房花燭夜當晚...
    茶點故事閱讀 45,092評論 2 355

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

  • 《Java從小白到大鸥崂》紙質(zhì)版已經(jīng)上架了!E佳姜凄! 由字符組成的一串字符序列,稱為“字符串”趾访,在前面的章節(jié)中也多次用到...
    tony關(guān)東升閱讀 816評論 0 2
  • 九種基本數(shù)據(jù)類型的大小态秧,以及他們的封裝類。(1)九種基本數(shù)據(jù)類型和封裝類 (2)自動裝箱和自動拆箱 什么是自動裝箱...
    關(guān)瑋琳linSir閱讀 1,887評論 0 47
  • 相關(guān)概念 面向?qū)ο蟮娜齻€特征 封裝,繼承,多態(tài).這個應該是人人皆知.有時候也會加上抽象. 多態(tài)的好處 允許不同類對...
    東經(jīng)315度閱讀 1,943評論 0 8
  • 由于時間倉促,有些地方未寫完,后面會繼續(xù)補充.如有不妥之處,歡迎及時與我溝通. 如果你也是在學習java,給你們推...
    分不清java閱讀 2,835評論 0 15
  • 山林中彎彎曲曲的道路扼鞋,繞繞彎彎申鱼,如果用相機拍攝下來,也許是一幅美麗的畫卷藏鹊;藍天白云下润讥,青山矗立,逶迤的小道再加幾只...
    柒而漆閱讀 144評論 0 0