Java的編譯期優化 因為工作的原因,經常會在沒有源碼的情況下,對一些產品的代碼進行閱讀。有時在解決Bug時,在運行環境下會直接去看class文件的位元組碼,來確定運行中版本是否正確的。 在看位元組碼時,發現了一個有意思的現象:即便你在代碼中使用了定義的常量,反編譯後的代碼仍會是字元串的字面量。 這個其 ...
Java的編譯期優化
因為工作的原因,經常會在沒有源碼的情況下,對一些產品的代碼進行閱讀。有時在解決Bug時,在運行環境下會直接去看class文件的位元組碼,來確定運行中版本是否正確的。
在看位元組碼時,發現了一個有意思的現象:即便你在代碼中使用了定義的常量,反編譯後的代碼仍會是字元串的字面量。
這個其實就是Java編譯器在編譯時做了優化,下麵就用一個例子來說明一下:
public class StringTest { public static final String a1="a"; public static String a2="a"; public static void main(String[] args) { String a = "a"; final String b = "b"; final String c = a + b; String d = a + b; String e = a + "b"; String f = "a" + b; String g = "a" + "b"; String h = "ab"; String i = new String(h); String j = a1+b; String k = a2+b; System.out.println(c == h); // false System.out.println(d == h); // false System.out.println(e == h); // false System.out.println(f == h); // true System.out.println(g == h); // true System.out.println(i == h); // false System.out.println(j == h); // true System.out.println(k == h); // false // 字面量,final 都會在編譯期被優化,並且會被直接運算好 // 所以 f,g,j 在編譯期就直接變為"ab" // 因為a,a2是變數, 所以使用到a,a2的表達式,都是在運行時才去計算的 } }
使用 javap命令查看位元組碼如下:
結合localvariabletable,分析main執行的過程如下:
從這裡面,可以很明顯的看到 運行時載入到f,g,h,j 時,直接就是字面量“ab”。
java中的==的作用是值的比較:
1)對於boolean,int,char,short,double,float,byte,long 這8種基本類型的比較,是比較值是否相等。
2)對於對象的比較,是比較地址的。
字元串字面量,和用final 修飾的 boolean,int,char,short,double,float,byte,long的變數一樣,被統稱為常量,它們是存在於常量池中的。
常量池中的內容只保留一份。上面例子中的f,g,j,h都是常量,它們的地址是同一個。所以比較的結果就是true。
而其它的,都是在運行時計算出來的,他們是在heap記憶體區域的(與常量池不在同一區域),所以他們的地址也就不一樣了。所以比較的結果就是false了。
同理,對於其它的 boolean,int,char,short,double,float,byte,long常量 ,也會在編譯期進行優化的。