2008-12-16 80 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.-