java編譯器對string常量表達式的處理和優化

首先把問題擺出來,先看這個代碼 
java

String a = "ab"; 
String b = "a" + "b"; 
System.out.println((a == b));

打印結果會是什麼?相似這樣的問題,有人考過我,我也拿來考過別人(蠻好玩的,你們也能夠拿來問人玩),通常答案會是如下幾種: 

1.true 
    "a" + "b" 的結果就是"ab",這樣a,b都是"ab"了,內容同樣因此"相等",結果true 
    通常java新人如是答。 jvm

2.false 編輯器

    "a" + "a"會生成新的對象"aa",可是這個對象和String a = "ab";不一樣,(a == b)是比較對象引用,所以不相等,結果false ,對java的String有必定了解的一般這樣回答。 優化

3.true 
    String a = "ab";建立了新的對象"ab"; 再執行String b = "a" + "b";結果b="ab",這裏沒有建立新的對象,而是從JVM字符串常量池中獲取以前已經存在的"ab"對象。所以a,b具備對同一個string對象 的引用,兩個引用相等,結果true. 
    能回答出這個答案的,基本已是高手了,對java中的string機制比較瞭解。 
    很遺憾,這個答案,是不夠準確的。或者說,根本沒有運行時計算b = "a" + "b";這個操做.實際上運行時只有String b = "ab"; 
    3的觀點適合解釋如下狀況: 
code

    String a = "ab"; 
    String b = "ab"; 
    System.out.println((a == b));

    若是String b = "a" + "b";是在運行期執行,則3的觀點是沒法解釋的。運行期的兩個string相加,會產生新的對象的。(本文後面對此有解釋) 對象

4.true 
    下面是個人回答:編譯優化+ 3的處理方式 = 最後的true 
字符串

    String b = "a" + "b";//編譯器將這個"a" + "b"做爲常量表達式,在編譯時進行優化,直接取結果"ab",這樣這個問題退化 
    String a = "ab"; 
    String b = "ab"; 
    System.out.println((a == b));

    而後根據3的解釋,獲得結果true 
    這裏有一個疑問就是String不是基本類型,像 
get

    int secondsOfDay = 24 * 60 * 60;

    這樣的表達式是常量表達式,編譯器在編譯時直接計算容易理解,而"a" + "b" 這樣的表達式,string是對象不是基本類型,編譯器會把它當成常量表達式來優化嗎? 
    下面簡單證實個人推斷,首先編譯這個類: 
編譯器

public class Test { 
    private String a = "aa"; 
}

       複製class文件備用,而後修改成 
string

public class Test { 
    private String a = "a" + "a"; 
}

    再次編譯,用ue之類的文本編輯器打開,察看二進制內容,能夠發現,兩個class文件徹底一致,連一個字節都不差. 
    ok,真相大白了.根本不存在運行期的處理String b = "a" + "b";這樣的代碼的問題,編譯時就直接優化掉了。 

下面進一步探討,什麼樣的string + 表達式會被編譯器當成常量表達式? 
String b = "a" + "b"; 
這個String + String被正式是ok的,那麼string + 基本類型呢? 

String a = "a1"; 
String b = "a" + 1;	
System.out.println((a == b));  //result = true 

String a = "atrue"; 
String b = "a" + true; 
System.out.println((a == b));  //result = true 

String a = "a3.4"; 
String b = "a" + 3.4; 
System.out.println((a == b));  //result = true

可見編譯器對string + 基本類型是當成常量表達式直接求值來優化的。 
再注意看這裏的string都是"**"這樣的,咱們換成變量來試試: 

String a = "ab"; 
String bb = "b"; 
String b = "a" + bb; 
System.out.println((a == b));   //result = false

這個好理解,"a" + bb中的bb是變量,不能進行優化。這裏很很好的解釋了爲何3的觀點不正確,若是String+String的操做是在運行時進行的,則會產生新的對象,而不是直接從jvm的string池中獲取。 
再修改一下,把bb做爲常量變量: 

String a = "ab"; 
final String bb = "b"; 
String b = "a" + bb; 
System.out.println((a == b));   //result = true

居然又是true,編譯器的優化好厲害啊,呵呵,考慮下面這種狀況: 

String a = "ab"; 
final String bb = getBB(); 
String b = "a" + bb; 
System.out.println((a == b));    //result = false 
private static String getBB() { 
return "b"; 
}

看來java(包括編譯器和jvm)對string的優化,真的是到了極點了,string這個所謂的"對象",徹底不能夠當作通常的對象,java對string的處理近乎於基本類型,最大限度的優化了幾乎能優化的地方。

相關文章
相關標籤/搜索