參考《think in Java》第四版 第十三章 13.2 重載“+”與StringBuilder
上原書代碼:
public class Concatenation{ public static void main(String args[]){ String mango = "mango"; String str = "abc" + mango + "deg" + 47; System.out.println(str); } }
.class文件 反編譯
javac Concatenation.java
javap -c Concatenation

結論:等同於new StringBuilder().append("abc").append(mango).append("deg").append(47).toString();
思考:常見的一個問題String Str = "a" + "b" + "c";生成了幾個String對象,或者生成了幾個對象。
看《think in java》的例子很容易進入誤區:new StringBuilder.append("a").append("b").append("c");下面看個例子:
public class StringTest{ public static void main(String args[]){ String str = "a" + "b" + "c"; String str2 = str + "d" + "f";
String str3 = str + "d" + "f" + 47 + "g"; } }

可以看出 String str = "a" + "b" = “c”; 在編譯期直接編譯成String str = "abc";
后面String Str2 = str + "d" + "f";在編譯期編譯成String str2 = new StringBuilder().append("abc").append("df").toString();
后面String Str3 = str + "d" + "f" + 47 +"g";在編譯期編譯成String str2 = new StringBuilder().append("abc").append("d").append(47).append("g").toString();
為什么
java編譯期有應用到“合並已知量”的優化技術。
這里我去找了下編譯原理關於代碼優化相關的知識
代碼優化的分類:
根據設計程序范圍分類:全局優化,局部優化,循環優化
根據技術的分類:
刪除多余運算:對於相同的子表達式,在第一次出現時進行計算,且值計算一次,其結果帶入ti,以后重復的地方直接帶入ti,不重復運算,節約時間及空間
強度削弱:在不改變運算結果的前提下,將程序中執行時間長的運算替換成執行時間短的運算。x^3可用x*x*x實現
合並已知量:若參加運算的兩個量都是已知量,則在編譯時直接計算出結果。1+2編譯期直接3
復寫傳播:盡量不引用那些程序中只傳遞信息而不改變值,不影響運行結果的變量。
循環優化:將循環中的不變量提到循環外面。
所以String str = "a' +“b” +"c";合並已知量為String str = "abc";
其實《think in java》中在提到final關鍵字時有一段話,表明java編譯時應用了此技術:
一個永不改變的編譯期常量:對於編譯期常量這種情況,編譯期可以將該常量值帶入到任何可能運用到的計算式中,也就是說可以在編譯時執行計算式,減輕運行時的負擔,但這類常量必須是基本數據類型,且必須final修飾初始化。
所以綜上,不結合上下文String Str2 = str + "d" + "f"中str是未知的。編譯時優化為StringBuilder,有趣的是后面的“d”+"f"合並了,然后str3中我們看到了並沒有合並為"df47e"
String str = "a" + "b" + "c";編譯為String str = "abc"; 建立了一個String對象“abc”。
另外查找資料的時候發現一個名詞StringPool(字符串常量池)
由於java對String操作頻繁,所以對String類做了很多優化,StringPool就是其中之一,StringPool是運行期維護於常量池中,處於GC永久代。
創建String對象的兩種方式
String str = new String("aa"); String str = "aa";
"aa"會存入StringPool,當下次使用時“aa”,String會先到StringPool查找“aa”,找到了把地址賦給引用對象,也就是指向同一對象(內存),沒找到建立新對象。
String str = "a"; String str2 = "a"; System.out.println(str == str2);//true
當然無論何時,new 一個對象都會創建一個新的對象。
拓展;Integer類的cache機制
