先看看下面的代碼
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();
}
講的好像有點道理,但是我用jad試了,反編譯後的文件並不是他說的那樣?那位試出來告訴一聲!!!