[導(dǎo)入]Java編譯器對于String常量表達(dá)式的優(yōu)化
首先把問題擺出來,先看這個代碼
|
打印結(jié)果會是什么?類似這樣的問題,有人考過我,我也拿來考過別人(蠻好玩的,大家也可以拿來問人玩),一般答案會是以下幾種:
1.true
"a" + "b" 的結(jié)果就是"ab",這樣a,b都是"ab"了,內(nèi)容一樣所以"相等",結(jié)果true
一般java新人如是答。
2.false
"a" + "a"會生成新的對象"aa",但是這個對象和String a = "ab";不同,(a == b)是比較對象引用,因此不相等,結(jié)果false
對java的String有一定了解的通常這樣回答。
3.true
String a = "ab";創(chuàng)建了新的對象"ab"; 再執(zhí)行String b = "a" + "b";結(jié)果b="ab",這里沒有創(chuàng)建新的對象,而是從JVM字符串常量池中獲取之前已經(jīng)存在的"ab"對象。因此a,b具有對同一個string對象的引用,兩個引用相等,結(jié)果true.
能回答出這個答案的,基本已經(jīng)是高手了,對java中的string機(jī)制比較了解。
很遺憾,這個答案,是不夠準(zhǔn)確的。或者說,根本沒有運(yùn)行時計算b = "a" + "b";這個操作.實(shí)際上運(yùn)行時只有String b = "ab";
3的觀點(diǎn)適合解釋以下情況:
|
如果String b = "a" + "b";是在運(yùn)行期執(zhí)行,則3的觀點(diǎn)是無法解釋的。運(yùn)行期的兩個string相加,會產(chǎn)生新的對象的。(本文后面對此有解釋)
4.true
下面是我的回答:編譯優(yōu)化+ 3的處理方式 = 最后的true
String b = "a" + "b";編譯器將這個"a" + "b"作為常量表達(dá)式,在編譯時進(jìn)行優(yōu)化,直接取結(jié)果"ab",這樣這個問題退化
|
然后根據(jù)3的解釋,得到結(jié)果true
這里有一個疑問就是String不是基本類型,像
int secondsOfDay = 24 * 60 * 60;
這樣的表達(dá)式是常量表達(dá)式,編譯器在編譯時直接計算容易理解,而"a" + "b" 這樣的表達(dá)式,string是對象不是基本類型,編譯器會把它當(dāng)成常量表達(dá)式來優(yōu)化嗎?
下面簡單證明我的推斷,首先編譯這個類:
|
復(fù)制class文件備用,然后修改為
|
再次編譯,用ue之類的文本編輯器打開,察看二進(jìn)制內(nèi)容,可以發(fā)現(xiàn),兩個class文件完全一致,連一個字節(jié)都不差.
ok,真相大白了.根本不存在運(yùn)行期的處理String b = "a" + "b";這樣的代碼的問題,編譯時就直接優(yōu)化掉了。
下面進(jìn)一步探討,什么樣的string + 表達(dá)式會被編譯器當(dāng)成常量表達(dá)式?
String b = "a" + "b";
這個String + String被正式是ok的,那么string + 基本類型呢?
|
可見編譯器對string + 基本類型是當(dāng)成常量表達(dá)式直接求值來優(yōu)化的。
再注意看這里的string都是"**"這樣的,我們換成變量來試試:
|
這個好理解,"a" + bb中的bb是變量,不能進(jìn)行優(yōu)化。這里很很好的解釋了為什么3的觀點(diǎn)不正確,如果String+String的操作是在運(yùn)行時進(jìn)行的,則會產(chǎn)生新的對象,而不是直接從jvm的string池中獲取。
再修改一下,把bb作為常量變量:
|
竟然又是true,編譯器的優(yōu)化好厲害啊,呵呵,考慮下面這種情況:
|
看來java(包括編譯器和jvm)對string的優(yōu)化,真的是到了極點(diǎn)了,string這個所謂的"對象",完全不可以看成一般的對象,java對string的處理近乎于基本類型,最大限度的優(yōu)化了幾乎能優(yōu)化的地方。
另外感嘆一下,string的+號處理,算是java語言里面唯一的一個"運(yùn)算符重載"(接觸過c++的人對這個不會陌生)吧?
文章來源:http://www.aygfsteel.com/supercrsky/articles/166463.html