[原創]關於Java String物件建立問題解惑

銀河使者發表於2008-03-22

先看看下面的程式碼

    public String makinStrings()
    {
        String s = "Fred";
        s = s + "47";
        s = s.substring(2, 5);
        s = s.toUpperCase();
        return s.toString();
    }

 

問:呼叫makinStrings方法會建立幾個String物件呢。  答案:3個

 

    上面的方法有五條語句:現在讓我們來一條一條分析一下。

String s = "Fred";   結論:建立了一個String物件

這條語句相當於String s = new String("Fred");
因此,毫無疑問,第一條語句建立了一個String物件,我想沒有有疑問吧?

s = s + "47";   結論:未建立String物件

這條語句也許很多人認為是建立了String物件,我一開始也是這麼認為的。但是為了驗證我的想法。決定
用點法術恢復這條語句的本來面目。(有很多時候,編譯器總是在裡面搞一些小動作,javac.exe也不例外)

現在找到這個程式所生成的.class檔案(假設是Test.class),找一個反編譯工具,我推薦JAD,可以http://www.softpedia.com/progDownload/JAD-Download-85911.html下載
下載後,有一個jad.exe,將其路徑放到環境變數path中(只限windows)。並在.class檔案的當前路徑執行如下的命令:

jad Test

然後大喊一聲“還我本來面目” 

會在當前目錄下生成一個Test.jad檔案,開啟它,檔案內容如下:

... ...
    public String makinStrings()
    {
        String s = "Fred";
        s = (new StringBuilder(String.valueOf(s))).append("47").toString();
        s = s.substring(2, 5);
        s = s.toUpperCase();
        return s.toString();
    }
... ...

哈哈,其他的語句都沒變,只有第二條變長了,雖然多了個new,但是建立的是StringBuilder物件。原來
這是java編譯器的優化處理。原則是能不建String物件就不建String物件。而是用StringBuilder物件
加這些字串連線起來,相當於一個字串佇列。這種方式尤其被使用在迴圈中,大家可以看看下面的程式碼:
        String s = "";
        for(int i=0; i < 10000000; i++)
            s += "aa";
沒有哪位老大認為這是建立了10000000個String物件吧。但不幸的是,上面的程式碼雖然沒有建立10000000個String物件
但卻建立了10000000個StringBuilder物件,那是為什麼呢,自已用jad工具分析一下吧。
正確的寫法應該是:

        StringBuilder sb = new StringBuilder("");
        for(int i=0; i < 10000000; i++)
            sb.append(String.valueOf(i));

 s = s.substring(2, 5);     結論:建立了一個String物件
 也許有很多人一開始就認為這條語句是建立了一個String物件,那麼恭喜你,這條語句確實建立了一個String物件
 實際上就是substring方法建立了一個String物件。這也沒什麼複雜的,自已下一個JDK原始碼,看看substring是如何實現的
 就可以知道了。我先說一下吧。先不用管substring是如何實現的,反正在substring方法返回時使用了一個new顯式地建立了一個String物件
 不信自己看看原始碼。
s = s.toUpperCase();   結論:建立了一個String物件

toUpperCase()和substring方法類似,在返回時也是使用了new建立了一個String物件。

return s.toString();   結論:未建立String物件

toString方法返回的就是this,因此,它的返回值就是s。

這道題還算比較簡單,再給大家出一個更復雜一點的,也是關於String物件的建立的(只是改了一個原題)。

    public String makinStrings()
    {
        String s = "Fred"; 
        s = s + "Iloveyou.".substring(1).toLowerCase();
        s = s.substring(0);
        s = s.substring(0,1).toUpperCase();
        return s.toString();
    }

先公佈答案吧,上述程式碼也建立了3個String物件,哈哈!

 

為什麼呢?

 

要想知道為什麼,先得弄清楚substring、toLowerCase和toUpperCase什麼時候建立String物件,什麼時候不建立物件。

substring方法在擷取的子字串長度等於原字串時,直接返回原字串。並不建立新的String物件。

toLowerCase方法在字串中更本沒有需要轉換的大寫字母時直接返回原字串,如"abcd".toLowerCase()直接返回abcd,並不建立新的String物件

toUpperCase方法和toLowerCase類似。"ABCD".toUpperCase()直接返回ABCD。

 

知道了這個,上面的程式碼就非常清楚了。

 

    public String makinStrings()
    {
        String s = "Fred";     // 建立一個String物件
        s = s + "Iloveyou.".substring(1).toLowerCase();  // substring(1)建立一個String物件,由於toLowerCase()轉換的字串是"loveyou.",沒有大寫字母,因此,它不建立新的String物件
        s = s.substring(0);   // 由於substring(0)截獲的是s本身,因此,這條語句不建立新的String物件
        s = s.substring(0,1).toUpperCase();  // substring(0,1)建立了一個String物件, 但由於substring(0,1)的結果是"F",為一個大寫字母,因此,toUpperCase直接返回"F"本身。
        return s.toString();
    }

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/12921506/viewspace-216924/,如需轉載,請註明出處,否則將追究法律責任。

相關文章