Why are strings immutable?

[ 2005-09-01 22:47:37 | 作者: admin ]
字号: | |
一直都想当然的接受了“strings are immutable”的事实,倒是没有仔细深入地想过原因。Google了一下,也没有找到满意的答案。我觉得大概有下面这些原因:

  避免字符串拷贝:如果String的内容可以改变,那么多个对象最好不要保存同一个字符串的引用,否则其中一个改变了String的内容就可能造成程序错误。这在多线程的环境下尤其重要,如果String不是immutable,那么它的所有编辑成员函数(Append, UpperCase等等)都必须要保证县城安全,性能损失惨重。如果每个对象保存String的一份Copy,则会消耗大量内存。Immutable实际上是一种近似于Copy-On-Write的折衷实现。
维护集合语义:String是最常用来作为集合(Map,Hashtable) 键值得类型,而一旦一个String对象被用作集合的键值,改变String的内容就会破坏集合的语义,造成程序错误。
String Interning: 几乎没有人在程序中显式调用过String.Intern方法,但是Interning可能是.NET对String做的最重要的优化。简单的说,CLR为系统中的所有常量字符串维护了一张Hash表,所谓Interning就是在这个Hash表中找到一个动态生成的字符串的等值对象。通常比较两个String是否相等我们需要逐个字符的比较,但是如果两个String都经过Interning处理,因为Hashtable中的String都是唯一的,我们只需要比较这两个String的引用是否相等(是否指向同一个对象)。下面是String.Intern的一个简单的例子:
               bool StringEquals(string a, string b) {
                    string ia = string.Intern(a);
                    string ib = string.Intern(b);
                    return Object.ReferenceEquals(ia, ib);
               }
          C#编译器在两个地方隐含的使用了String Interning: 1) 如果在源代码中多次出现同样的字符串,只有一个对应的String会被放在CLR的StringPool当中,这个String对象会在代码中多次引用到。2) C/C++不支持基于String的switch/case,但是C#支持,这就是通过Intern实现的:C#编译器先把switch对应的字符串进行Interning处理,然后和下面的case进行引用比较就可以了。
          显然,String的Intern语义依赖于其不可变性:如果系统Intern Pool中的字符串可能会被改变,CLR就不能隐式的重用这些对象。
评论Feed 评论Feed: http://blog.xg98.com/feed.asp?q=comment&id=156

这篇日志没有评论。

此日志不可发表评论。