我的漫漫程序之旅

          專(zhuān)注于JavaWeb開(kāi)發(fā)
          隨筆 - 39, 文章 - 310, 評(píng)論 - 411, 引用 - 0
          數(shù)據(jù)加載中……

          Java編譯器對(duì)于String常量表達(dá)式的優(yōu)化

           

          首先把問(wèn)題擺出來(lái),先看這個(gè)代碼

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

          打印結(jié)果會(huì)是什么?類(lèi)似這樣的問(wèn)題,有人考過(guò)我,我也拿來(lái)考過(guò)別人(蠻好玩的,大家也可以拿來(lái)問(wèn)人玩),一般答案會(huì)是以下幾種:

          1.true

          "a" + "b" 的結(jié)果就是"ab",這樣a,b都是"ab"了,內(nèi)容一樣所以"相等",結(jié)果true

          一般java新人如是答。

          2.false

          "a" + "a"會(huì)生成新的對(duì)象"aa",但是這個(gè)對(duì)象和String a = "ab";不同,(a == b)是比較對(duì)象引用,因此不相等,結(jié)果false

          對(duì)java的String有一定了解的通常這樣回答。

          3.true

          String a = "ab";創(chuàng)建了新的對(duì)象"ab"; 再執(zhí)行String b = "a" + "b";結(jié)果b="ab",這里沒(méi)有創(chuàng)建新的對(duì)象,而是從JVM字符串常量池中獲取之前已經(jīng)存在的"ab"對(duì)象。因此a,b具有對(duì)同一個(gè)string對(duì)象的引用,兩個(gè)引用相等,結(jié)果true.

          能回答出這個(gè)答案的,基本已經(jīng)是高手了,對(duì)java中的string機(jī)制比較了解。

          很遺憾,這個(gè)答案,是不夠準(zhǔn)確的?;蛘哒f(shuō),根本沒(méi)有運(yùn)行時(shí)計(jì)算b = "a" + "b";這個(gè)操作.實(shí)際上運(yùn)行時(shí)只有String b = "ab";

          3的觀點(diǎn)適合解釋以下情況:

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

          如果String b = "a" + "b";是在運(yùn)行期執(zhí)行,則3的觀點(diǎn)是無(wú)法解釋的。運(yùn)行期的兩個(gè)string相加,會(huì)產(chǎn)生新的對(duì)象的。(本文后面對(duì)此有解釋)

          4.true

          下面是我的回答:編譯優(yōu)化+ 3的處理方式 = 最后的true

          String b = "a" + "b";編譯器將這個(gè)"a" + "b"作為常量表達(dá)式,在編譯時(shí)進(jìn)行優(yōu)化,直接取結(jié)果"ab",這樣這個(gè)問(wèn)題退化

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

          然后根據(jù)3的解釋?zhuān)玫浇Y(jié)果true

          這里有一個(gè)疑問(wèn)就是String不是基本類(lèi)型,像

          int secondsOfDay = 24 * 60 * 60;

          這樣的表達(dá)式是常量表達(dá)式,編譯器在編譯時(shí)直接計(jì)算容易理解,而"a" + "b" 這樣的表達(dá)式,string是對(duì)象不是基本類(lèi)型,編譯器會(huì)把它當(dāng)成常量表達(dá)式來(lái)優(yōu)化嗎?

          下面簡(jiǎn)單證明我的推斷,首先編譯這個(gè)類(lèi):

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

          復(fù)制class文件備用,然后修改為

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

          再次編譯,用ue之類(lèi)的文本編輯器打開(kāi),察看二進(jìn)制內(nèi)容,可以發(fā)現(xiàn),兩個(gè)class文件完全一致,連一個(gè)字節(jié)都不差.

          ok,真相大白了.根本不存在運(yùn)行期的處理String b = "a" + "b";這樣的代碼的問(wèn)題,編譯時(shí)就直接優(yōu)化掉了。

          下面進(jìn)一步探討,什么樣的string + 表達(dá)式會(huì)被編譯器當(dāng)成常量表達(dá)式?

          String b = "a" + "b";

          這個(gè)String + String被正式是ok的,那么string + 基本類(lèi)型呢?

          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

          可見(jiàn)編譯器對(duì)string + 基本類(lèi)型是當(dāng)成常量表達(dá)式直接求值來(lái)優(yōu)化的。

          再注意看這里的string都是"**"這樣的,我們換成變量來(lái)試試:

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

          這個(gè)好理解,"a" + bb中的bb是變量,不能進(jìn)行優(yōu)化。這里很很好的解釋了為什么3的觀點(diǎn)不正確,如果String+String的操作是在運(yùn)行時(shí)進(jìn)行的,則會(huì)產(chǎn)生新的對(duì)象,而不是直接從jvm的string池中獲取。

          再修改一下,把bb作為常量變量:

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

          竟然又是true,編譯器的優(yōu)化好厲害啊,呵呵,考慮下面這種情況:

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

          看來(lái)java(包括編譯器和jvm)對(duì)string的優(yōu)化,真的是到了極點(diǎn)了,string這個(gè)所謂的"對(duì)象",完全不可以看成一般的對(duì)象,java對(duì)string的處理近乎于基本類(lèi)型,最大限度的優(yōu)化了幾乎能優(yōu)化的地方。

          另外感嘆一下,string的+號(hào)處理,算是java語(yǔ)言里面唯一的一個(gè)"運(yùn)算符重載"(接觸過(guò)c++的人對(duì)這個(gè)不會(huì)陌生)吧?



          posted on 2007-12-09 16:07 々上善若水々 閱讀(867) 評(píng)論(0)  編輯  收藏 所屬分類(lèi): J2SE

          主站蜘蛛池模板: 房产| 横山县| 柞水县| 丘北县| 翁源县| 汉阴县| 太保市| 和顺县| 永泰县| 岱山县| 北安市| 乌审旗| 喀什市| 南和县| 林西县| 吴旗县| 云安县| 福州市| 龙川县| 东城区| 兰考县| 平阳县| 循化| 明水县| 长宁县| 富裕县| 得荣县| 舒城县| 林周县| 内黄县| 资源县| 左云县| 旌德县| 防城港市| 北辰区| 北安市| 西林县| 民丰县| 阳高县| 栾城县| 辉南县|