关于string中涉及到的暂存池
之前看了一些string相关的博客,感觉写的挺好,但终究还是没深究。哎,学习最怕就是我这种心态了吧!
今天看了一些C#相关的面试题,其中一题感觉很简单,题目如下:
string a = "abc";
a = (a.ToUpper()+"123").SubString(0,2);
问上述代码运行时总共会产生多少个临时对象?
自己看了下,应该是5个:
ToUpper()会产生一个”ABC”,“123”算一个,“ABC”+”123”=”ABC123”又是一个,SubString()也会产生一个(“AB”),再加上a本身的那个,总共是5个。
但是自己想了想,应该如何验证自己的想法呢?避免出现模棱两可的情况。所以打算亲自验证下,但是验证也无法实际验证,因为这些都是临时变量,它们并没有一个变量来存储,所以用调试的方式来验证也是不太可行的。
无奈,只能将上面的代码改成如下:
static void Main()
{
string a = "abc";
string b = a.ToUpper();
string c = "123";
string d = b + c;
string e = d.Substring(0, 2);
string f = "AB";
}
然后用调试的方法来查看各个字符串变量的内存地址。
本以为应该会很快解决这个问题,但调试了一遍之后发现不对劲!记得之前看的string相关的博客里提到过,两个完全相同的字符串(string对象),他们在C#中引用的会是同一块内存地址。但上面的调试结果却让我傻眼了。变量e和f的值是一样的,但是它们的地址却不一样!这是为何?
后来又看了下之前的那篇文章:《你真的了解.NET中的String吗?》,发现这篇文章中其实也提到了我遇到的问题,只是没有明确说明。这对于还是小白的我来说,由于不了解C#中String类的暂存池机制,所以之前也是略知一二,知道相同字符串引用的是同一块内存,但却忽略了一个严重的前提!这个字符串前提是必须在暂存池当中。
而查到这个暂存池主要是因为看到了String.Intern(string)这个静态方法。查了下,正好查到了要找的内容:
《囧,对C#驻留池(Intern Pool)机制的误解》。
这里简单讲解了暂存池,也就是驻留池的一些机制:
驻留池由CLR来维护,其中的所有字符串对象的值都不相同
驻留池中的所有字符串都不一样,以此来保证相同字符串的引用地址是相同的。只有编译阶段的文本字符常量会被自动添加到驻留池,运行时期动态创建的字符串不会被加入到驻留池中
这也就是为什么我上面调试的时候发现e和f的地址不一样的原因了。这里也很好理解,因为f的值在编译阶段就已经确定了的,是静态的文字常量,而e的值是经过运行产生的,所以e的值不会被存放到Intern Pool中。- 可以使用静态方法String.Intern(string)把动态创建的字符串加入到驻留池中
要使e和f的引用相同,使用这个方法即可。