System.String是不可变的字符串吗?
在学习.net编程时,你一定有听到过这样的说法,System.String
类是不可变字符串,也就是说你不能修改一个字符串的值。
比如以下这段代码
string s = "hello";
s = "world";
你并不是把s
的值修改为world
,而是生成了一个新的包含"world"的字符串,然后令s这个字符串的引用指向新的字符串,而原来的那个字符串就被抛弃掉了。
也正是基于String
类的不可修改性,CLR采用了String Interning的技术来共享相同的字符串,以达到减少内存使用的目的。比如以下这段代码
string s1 = "hello";
string s2 = "hello";
if (Object.ReferenceEquals(s1, s2))
Console.WriteLine("They are same");
s1
和s2
其实指向相同的字符串。
那么是不是我们真的没有办法改变一个string的值呢?当然不是,在C++/CLI中,我们可以使用一些特殊的手段来达到我们的目的!
String^ s1 = "hello";
String^ s2 = "hello";
interior_ptr<Char> p = const_cast<interior_ptr<Char> >(PtrToStringChars(s1));
for(; *p; *p++='a');
Console::WriteLine("{0} and {1}",s1,s2);
PtrToStringChars(String^)
是一个定义在vcclr.h
头文件中的一个helper function,它返回一个类型为interior_ptr<const Char>
的内部指针,指向String实例内部所包含的字符串,之所以返回类型是interior_ptr<const Char>
而不是interior_ptr<Char>
是因为不希望我们改变String
实例内的字符串,不过既然我们执意要这么做,那么就让我们用一个const_cast<T>
来把这个const
搞掉!
运行以上代码你会发现,s2
现在的内容已经是aaaaa
,而不是hello
了。
当然,以上例子只是说明存在修改string
实例的内容的可能,并不是鼓励大家这么做。虽然直接访问string
实例内部的字符串,可能会带来一些性能上的好处。但是由于String Interning的存在,修改String实例内部的字符串是相当危险的行为,比如上面的那个例子中,你会发现,s1的输出也变成aaaaa了!
posted on 2004-12-07 22:15 Justin Shen 阅读(2415) 评论(4)
Feedback
1楼 2004-12-07 22:49 林
string s1 = "hello";
string s2 = "hello";
if (Object.ReferenceEquals(s1, s2))
Console.WriteLine("They are same");
s1
和s2
其实指向相同的字符串。
你说错了,或者是你说的比较含糊ReferenceEquals
对于引用类型来说,完全和==
等同
这点必须明白
对值类型来说,是把他们box成oject对象在进行==
比较
2楼 [楼主] 2004-12-07 23:05 Justin Shen
string的==操作是重载过的,其结果取决于string引用所指向的字符串的内容是否相同,而不仅当指向同一个字符串时,才会返回true,这并不同于Object.
ReferenceEquals(),考虑以下的代码:
string s1 = "hello";
StringBuilder builder = new StringBuilder("hello");
string s2 = builder.ToString();
if (!Object.ReferenceEquals(s1, s2))
Console.Write("the two string references don't refer to the same string object, ");
if (s1 == s2)
Console.WriteLine("whereas the two strings themselves are equal.");
3楼 2004-12-07 23:07 林
不好意思我说错了
原谅
4楼 2004-12-08 09:23 fans1
C#也可以用指针达到修改的目的,不一定需要c++/cli来