一:前言
String和StringBuilder都是引用类型
StringBuilder是可变的字符串,它不会创建当前字符串的新修改实例而是在现有字符串对象中进行修改
String是不可变字符串,一旦被初始化后就不能改变其内容,String值改变的过程其实是创建了一个新的String对象赋值给了原对象(引用的改变)
如果有大量的字符串修改、拼接操作则使用StringBuilder会极大的减少系统的开销
二:使用String连接字符串
例如实例化一个字符串string str="my",str对象的内存地址指向了堆里面的my,当使用str+="name"时,并不是改变my的值,而是在堆中分配了一段新的内存空间"myname“并引用给str,本质是创建了一个新的字符串赋值给了str。试想一下假如在循环中执行多次修改字符串操作,将会产生大量垃圾内存。而StringBuilder只会在实例化时或Capacity不够扩容时分配内存
三:String不可变的好处
——线程安全
——因为字符串的不可变特性,所以其可以放心地作为Dictionary的键,使用可变类型作为键是极其危险的事,因为可修改键可能会导致Dictionary中键值的唯一性被破坏
四:常量池
string str = "liu";
private void Update()
{
str = "yin";
}
现在我们了解到字符串是不可变的,每次修改都会分配一个新的内存空间,但在Unity中运行上面的代码,用性能工具查看,发现并没有分配额外的内存,这是为什么呢?
下面介绍一下C#中的常量池,顾名思义,与对象池的作用一样,将常量放入一个池子中,每当创建字符串对象时,首先会检查字符串常量池中是否存在面值相等的字符串,如果有就不再创建,直接返回常量池中对该对象的引用,如果没有就创建,放到常量池中并且返回新建对象的引用
string str1 = "Hello";
string str2 = "Hello";
例如上面的两句代码str1和str2的地址是相同的,创建str1时先查找字符串池中是否存在字符串hello,发现并没有于是分配一个新的内存,当创建str2时,在字符串池找到了hello,则不需要再创造新值
如果使用下面的方式则会分配新的内存
string str1 = new string("Hello".ToCharArray());
string str2 = new string("Hello".ToCharArray());
但是并不是所有直接赋值的对象都会被放入常量池,只有编译阶段的字符串才会,动态的字符串是不会被放入进常量池中的,因为值是不固定的放入池中无意义,例如DateTime.Now
所以创建字符串或修改字符串值的时候尽量要使用直接赋值(string str = “”),这样会被放入常量池中进行复用,减少没必要的内存分配