C# 拼接字符串的几种方式和性能
开发过程中常用到的拼接字符串的方法有四种:
一般来讲,拼接速度:4>>3>2>1,即方法4远快于方法3,方法3略快于方法2,方法2略快于方法1
1. 简单 “+=” 拼接法
1
2
3
4
5
|
string str= "a" ; str+= "c" + "d" ; string str_1= "a" + "b" ; |
首先需要明白的是string类型,string是引用类型,保留在堆上,而不是栈上,用的时候传的是内存中的地址,每次修改就会重新创建一个新的string对象来存储字符串,原有的会被自动回收。
第一种方式的实现原理,第一步先在内存中分配空间,存储str变量的对象,值为"a", “+=”时,又会重新创建一个对象来存储新的字符串(“abc"),把str指向这个新的地址。所以只有简单几步的拼写时,一般不会有太大问题,如果有时候需要循环拼接时,就会不断创建新的对象,很浪费性能和内存。
2. String.Format()
1
|
string str= String.Format( "{0}{1}{2}" , "a" , "b" , "c" ); |
这就需要先看看他的源代码了,
1
2
3
4
5
6
7
|
public static String Format(IFormatProvider provider, String format, params Object[] args) <br>{ if (format == null || args == null ) throw new ArgumentNullException((format== null )? "format" : "args" ); StringBuilder sb = new StringBuilder(format.Length + args.Length * 8); sb.AppendFormat(provider,format,args); return sb.ToString(); } |
可以看到是先创建一个StringBuilder类型的变量,长度为第一个参数的长度+参数长度的8倍。.Net自动分配一个比较大的容量来存储。StringBuilder的介绍请看第4种方法.
这种方式的代码看起来比较整洁,易于阅读,效率也比+=高效很多。
3.string.concat()方法:
concat源代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | public String concat(String str) { // 追加的字符串长度 int otherLen = str.length(); // 如果追加的字符串长度为0,则不做修改,直接返回原字符串 if (otherLen == 0) { return this ; } // 获取原字符串的字符数组value的长度 int len = value.length; // 将原字符串的字符数组value放到buf字符数组中 char buf[] = Arrays.copyOf(value, len + otherLen); // 将追加的字符串转化成字符数组,添加到buf中 str.getChars(buf, len); // 产生一个新的字符串并返回 return new String(buf, true ); } |
整体是一个数组的拷贝,虽然在内存中是处理都是原子性操作,速度非常快,但是,最后的return语句创建一个新String对象,也就是每次concat操作都会创建一个新的String对象,这也是限制concat方法速度的原因。
4. StringBuilder.Append()
1
2
3
|
StringBuilder str= new StringBuilder(); str.Append( "a" ); |
StringBuilder 是预先创建一个比较大的内存,以后每次操作时判断容量上限是否不够用,如果不够用就自动把容量扩大一倍,修改的还是第一次创建的对象的值。
append()方法
append源代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | public AbstractStringBuilder append(String str) { // 如果是null值,则把null作为字符串处理 if (str == null ) return appendNull(); int len = str.length(); // 追加后的字符数组长度是否超过当前值 ensureCapacityInternal(count + len); // 字符串复制到目标数组 str.getChars(0, len, value, count); count += len; return this ; } private AbstractStringBuilder appendNull() { int c = count; ensureCapacityInternal(c + 4); final char [] value = this .value; value[c++] = 'n' ; value[c++] = 'u' ; value[c++] = 'l' ; value[c++] = 'l' ; count = c; return this ; } private void ensureCapacityInternal( int minimumCapacity) { // overflow-conscious code if (minimumCapacity - value.length > 0) expandCapacity(minimumCapacity); // 加长,并作数组拷贝 } |
整个append方法都在做字符数组的处理,加长,拷贝等,这些都是基本的数据处理,整个方法内并没有生成对象。只是最后toString返回一个对象而已。需要注意的是,append()方法返回的是一个StringBuilder(or StringBuffer)对象实例。
如果是简单的拼写时,可以用 "+=", string.format()
循环内拼写很长的字符串时,就需要用到StringBuilder来节省性能和内存了。 - -
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 25岁的心里话
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!
· 零经验选手,Compose 一天开发一款小游戏!