1.前言
string是属于引用类型的,这个大家都知道吧?但是平常在使用的过程中,发现它还是拥有一些值类型的特征的,这到底是为什么呢?
原因就是.Net考虑到假如大量的操作string对象的时候,大量对引用对象进行操作的时候,性能肯定不如值类型来的爽快。.Net为了提高这个性能,提供了一个专门的解决方案:字符串驻留池!
2.正文
先让我们来看一段代码:
1 string str1 = "aa"; 2 string str2 = "a" + "a"; 3 Console.WriteLine(ReferenceEquals(str1, str2)); //print:true
这str1跟str2的内存指向地址居然是一模一样的!
原因是.Net在CLR内部维护了一个Hash表(其实就是前文说的字符串驻留池),key为字符串内容,值就是所指向的托管堆的地址;当初始化创建了一个新的字符串的时候,.Net就会去这个Hash表中搜索是否有相同的值,如果key相同,就会把已经存在的字符串的地址值赋给新创建的字符串,如果不存在则重新分配地址,这就是为什么上面这个代码的内存为true。
再让我们来看另外一段代码:
1 string str3 = "ab"; 2 string str4 = "a"; 3 str4 += "b"; 4 Console.WriteLine(ReferenceEquals(str3, str4));//print :false
之所以出现了false,请注意上一栏的关键字“初始化创建”,当字符串是动态创建的时候,.Net并不会去Hash表中搜索是否有创建,而是直接创建;
假如想对上面的代码优化一下并且对性能有更(xian)高(de)追(dan)求(teng),我们可以手动将这个字符串加入到字符串驻留池中进行对比
1 string str3 = "ab"; 2 string str4 = "a"; 3 str4 += "b"; 4 str4 = string.Intern(str4);//Intern:它会去字符串驻留池中搜索,假如找寻到的话则返回对应的地址 5 Console.WriteLine(ReferenceEquals(str3, str4));//print :true
3.总结
最后对string下点结论:
1.string在clr中不是用newobj指令创建,而是用ldstr指令创建!而且string拥有值类型的特征,但是在内存上是引用类型,存在托管堆上面;
2.string是sealed修饰的,所以不能被子类集成;
3.当创建内容相同的时候,string是指向同一地址的,而且每次操作string都会生成新的地址(string的恒定性);
4.对于大量拼接的话还是使用StringBuilder,它是动态的不像string是恒定的,但就是创建StringBuilder代价比较大,所以小拼接用string在性能上可能还更好!
还有最后一个最后,卖点小广告:深圳地区招聘.Net开发工程师(医疗方向),有兴趣的小伙伴可以发送简历 (入职后我们将推荐奖金拿去上梅林的潮兴火锅吃了吧~)