2008-12-16 105 views
12

字符串不可變性是通過語句還是通過語句中的字符串工作?字符串不可變性

例如,我知道下面的代碼會在堆上分配兩個字符串。

string s = "hello "; 
s += "world!"; 

「hello」將留在堆上直到垃圾收集;現在引用「你好世界!」在堆上。但是,下列行在堆上分配了多少個字符串... 1或2?另外,有沒有一種工具/方法來驗證結果?

string s = "goodbye " + "cruel world!"; 

回答

21

編譯器提供了字符串連接,這是特殊待遇,爲什麼第二個例子是隻有永遠一個字符串。而「實習」意味着即使你運行這一行20000次,仍然只有1個字符串。

重新測試結果...最簡單的方法(在這種情況下)可能是反射鏡看:

.method private hidebysig static void Main() cil managed 
{ 
    .entrypoint 
    .maxstack 1 
    .locals init (
     [0] string s) 
    L_0000: ldstr "goodbye cruel world!" 
    L_0005: stloc.0 
    L_0006: ldloc.0 
    L_0007: call void [mscorlib]System.Console::WriteLine(string) 
    L_000c: ret 
} 

正如你可以看到(ldstr),編譯器已經做了這個給你。

+0

公平:在這種情況下,字符串的兩部分在編譯時已知。如果有任何部分必須等到運行時纔會看到一些非常不同的IL。 – 2008-12-16 20:12:18

+1

@Joel - 是的,但那是個問題。 – 2008-12-16 20:18:45

-1

如果編譯器是「智能」的,它只會是一個帶有「再見殘酷的世界!」的字符串!

+0

它是,它確實如此。在我的回覆中看到IL。 – 2008-12-16 19:25:40

+0

也做一個谷歌實習生池 – JamesSugrue 2008-12-16 19:29:27

0

實際上,可能是3.「goodbye」的常量字符串,「殘酷世界」的const字符串,然後是結果的新字符串。

您可以通過查看生成的代碼來確定。它依賴於編譯器(事實上,這在語言中並不明顯),但是你可以通過使用-a標誌(我認爲,檢查手冊頁)來讀取g ++的輸出以獲得中間代碼。

+0

這是.net他要求。 – 2008-12-16 19:35:24

0

不要相信你對字符串「知道」的內容。您可以通過源代碼查看字符串的實現。比如你的例子:

string s = "goodbye " + "cruel world!"; 

在java中會分配一個字符串。 Java扮演着一些非常可愛的技巧,並且很難超越智能 - 只有在需要時纔會進行優化!

然而,目前據我所知,使用這樣的:

String s=""; 
for(int i=0;i<1000;i++) 
    s+=" "; 

仍然創造1000空間字符串往往是極其低效

在一個循環中追加是非常糟糕的,但除此之外,它是大概和StringBuilder一樣高效。

+0

這是一個相當大的「否則」... StringBuilder將使用加倍,所以<10調整大小,而不是1000個副本(telescoping)。 – 2008-12-16 19:54:52

+0

對,現在,避免在大循環中追加字符串,但不要強調它。即使如此,對於大多數代碼我都不會擔心,直到它開始影響性能。 – 2008-12-16 20:03:19

3

文字串是interned這意味着"hello "確實駐留在堆但在數據段[見註釋]的編程'的(並且因此沒有資格垃圾收集),同樣適用於"world",至於"hello world",如果編譯器足夠聰明的話,它也可能被攔截。

"goodbye cruel world"由於字符串文字連接被編譯器處理,所以被攔截。


編輯:我不知道有關數據段聲明,請參閱this question以獲取更多信息。

0

這裏要小心,因爲當編譯時已知字符串值時,編譯器可以做出一些非常不同的優化。如果你使用的字符串直到運行時才知道(從配置文件,數據庫或用戶輸入中提取),你會看到一些非常不同的IL。

0

如果你只是要做一個或兩個字符串連接,我不會擔心它。

但是,如果你有很多連接,或者你有一個循環,那麼你一定要採取預防措施。在Java世界中,這意味着您使用StringBuffer代替連接字符串。

0

如果它不只在一行中,則可以通過將第一個字符串變成一個StringBuffer,進行連接並返回結果字符串來完成兩個字符串的連接。

創建的StringBuffer自己看似矯枉過正,但是這就是將要發生anyway.-