String的運算 重載"+"與StringBuilder


參考《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機制

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM