字符串对我编程人员来讲是字符串时天天见面的常客,你不认识不熟悉他都不得行,字符串的拼接更是屡见不鲜,那么在实际开发过程当中实现字符串的拼接有哪一些方式呢?我们一块儿来聊聊,来交流沟通,学习一波。也许你会说,那也太简单了嘛,谁不会啊,哈哈,使用起来确实简单,可是不必定咱们都使用的方式还有优秀的方式吗?html
在文章前,咱们先简单聊聊关于string的数据类型存储必须了解概念:程序员
string是一个引用类型,是一个sealed类,存储在堆内存上,每一次修改都会重新建立一个新的string来存储,原始的会自动被回收。这个是不感受是废话,人人都知道嘛,哈哈哈。编程
下面以c#为开发语言来讲明:实现字符串的拼接经常使用的方式有以下四种c#
其1、直接经过+拼接数组
直接经过+拼接是咱们在代码中最多见的一种方式,下面以一个简单的代码段来分析分析ide
1 string str="1"; 2 3 str=str+"2";
第一段代码,首先分配了一个内存空间来存储str变量,其值为“1”函数
第二段代码,从新分配了一个新的内存空间来存储“12”,并将str指向新地址性能
经过分析,其实咱们不难发现,两端就简单的代码,就会有两次内存地址操做,随着拼接字符串的个数地址,分配内存地址的次数也递增,当几个简单的字符串经过该方式拼接时,其实咱们仍是感受不到性能的影响,可是当字符串数量大时,你都会有感受了,那样不只仅形成内存的浪费,还直接影响性能。学习
因此在实际开发工程中,经过+拼接字符串比较常见,可是若是只是见到这种方式也就不那么友好了,既然不友好,那么显然就会有比较友好的方式啦,下面咱们就分析分析经过StringBuilder来实现字符串的拼接。测试
其2、经过StringBuilder拼接字符串
StringBuilder其实内部至关因而维护的一个字符数组,是一个能够动态增长自身数据长度,其默认长度为16,当存储的字符串超出其长度是,会自动扩容2倍长度。
哈哈,说到这儿,估计你看出了问题,那就是超出长度自动扩容,自动扩容是否是也须要牺牲性能,固然在几回扩容你还感受不到性能的影响,可是若是词数多了,你就会感受很明显,这也是对StringBuilder的一些使用技巧。
咱们去看不一样小伙伴的代码,你就会发现,技术老鸟,在初始化StringBuilder的时候会根据预估将要存储的字符串大小,给StringBuilder初始化一个长度,这也就是细节上的差距体现。
说了半天的废话,是否是要来的实际的代码来证实说的不是废话呢?不急不急,在文章最后,我会专门写测试代码对比分析的。
其3、string.Format不陌生吧
对于一些格式的数据拼接填充,string.Format也是常常看见的,他的一个很大好处就是,看上去比较清晰
其实咱们看过string的底层实现咱们会发现,其底层本质仍是StringBuilder来实现的
下面就是string.format的源码实现
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(); }
其实string.Format使用起来很简单,我就不在啰嗦介绍了,省得你们以为烦,哈哈哈
string result=string.Format("你们好,我叫{0},今年{1}","程序员修炼之旅",1);
其4、$方式拼接字符串
C#6.0出现了$方式拼接字符串,其实简单说就是string.Format简化操做版,string.Format若是拼接的字符串太多,估计本身都懵逼的分不清对应关系了,不知道大家遇到过没有,反正我原来是遇到过的。$就很好的规避了该问题,那么下 面来一个例子说明一切:
string name = "程序员修炼之旅"; int age = 1; string str = string.Format("my name is{0}, I'm {1} years old",name,age); string str2 = $"my name is{name}, I'm {age} years old";
最终结果是:str=str1
其五,固然还有其余方式,不在此啰嗦了,后续在讨论
测试分析
说了半天,不拿点实际东西来测试,我知道你是不会信服的,下面就直接上测试代码:
using System; using System.Diagnostics; using System.Text; namespace stringSplicingTest { /// <summary> /// 字符串拼接练习 /// </summary> public class Program { /// <summary> /// 主函数入口 /// </summary> /// <param name="args"></param> static void Main(string[] args) { // 测试分别经过+ 和 StringBuilder 来链接 0 之100的数字 Console.WriteLine("测试分别经过+ 和 StringBuilder 来链接"); Console.WriteLine(""); Console.WriteLine("测试链接 0 - 100 的数字"); Console.WriteLine(""); PlusString(100); StringBuilderString2(100); Console.WriteLine(""); Console.WriteLine(""); Console.WriteLine("测试链接 0 - 10000 的数字"); PlusString(10000); StringBuilderString2(10000); Console.WriteLine(""); Console.WriteLine(""); // 下面测试一下一样是StringBuilder链接字符串,一个是定义吃指定长度,一个是不指定长度对比 Console.WriteLine(@"下面测试一下一样是StringBuilder链接字符串, 一个是定义并指定长度,一个是不指定长度对比"); Console.WriteLine(""); Console.WriteLine("测试链接 0 - 1000000 的数字"); Console.WriteLine("不初始化长度"); StringBuilderString(1000000); Console.WriteLine("初始化长度"); StringBuilderString2(1000000); Console.WriteLine(""); Console.WriteLine(""); Console.WriteLine("测试链接 0 - 10000000 的数字"); Console.WriteLine("不初始化长度"); StringBuilderString(10000000); Console.WriteLine("初始化长度"); StringBuilderString2(10000000); Console.ReadLine(); } /// <summary> /// 经过+拼接字符串 /// </summary> /// <param name="totalNum"></param> private static void PlusString(int totalNum) { //// 定义一个秒表,执行获取执行时间 Stopwatch st = new Stopwatch();//实例化类 st.Start();//开始计时 Console.WriteLine("开始执行,经过+链接字符串:"); string result = ""; //// 定义一个数组 for (int i = 0; i < totalNum; i++) { result = result + i.ToString(); } //须要统计时间的代码段 st.Stop();//终止计时 Console.WriteLine(string.Format("执行完毕,经过+链接字符串!总耗时{0}毫秒", st.ElapsedMilliseconds.ToString())); } /// <summary> /// 经过s拼接字符串 /// </summary> /// <param name="totalNum"></param> private static void StringBuilderString(int totalNum) { //// 定义一个秒表,执行获取执行时间 Stopwatch st = new Stopwatch();//实例化类 st.Start();//开始计时 Console.WriteLine("开始执行,经过 StringBuilder 链接字符串:"); StringBuilder result = new StringBuilder(); //// 定义一个数组 for (int i = 0; i < totalNum; i++) { result.Append(i.ToString()); } string result2 = result.ToString(); //须要统计时间的代码段 st.Stop();//终止计时 Console.WriteLine(string.Format("执行完毕,经过 StringBuilder 链接字符串!总耗时{0}毫秒", st.ElapsedMilliseconds.ToString())); } /// <summary> /// 经过StringBuilder拼接字符串,初始化时指定一个长度 /// </summary> /// <param name="totalNum"></param> private static void StringBuilderString2(int totalNum) { //// 定义一个秒表,执行获取执行时间 Stopwatch st = new Stopwatch();//实例化类 st.Start();//开始计时 Console.WriteLine("开始执行,经过 StringBuilder 链接字符串:"); StringBuilder result = new StringBuilder(totalNum * 6); //// 定义一个数组 for (int i = 0; i < totalNum; i++) { result.Append(i.ToString()); } string result2 = result.ToString(); //须要统计时间的代码段 st.Stop();//终止计时 Console.WriteLine(string.Format("执行完毕,经过 StringBuilder 链接字符串!总耗时{0}毫秒", st.ElapsedMilliseconds.ToString())); } } }
结果分析总结:
测试分两个点:
其一测试的是:经过+和StringBuilder拼接字符串的性能比较哦
其二测试的是:StringBuilder初始化长度和不初始化长度的性能比较
大概得出如下几点结论
一、在待拼接的字符串少的时,+和StringBuilder没有明显的性能差距
二、当拼接的字符串多时,StringBuilder的优点愈来愈明显
三、一样是StringBuilder拼接字符串,预估初始化长度的效率比不初始化指定长度的效率高
说到此,我相信你们都知道该怎么使用了。好了,时间不早了,赶忙洗洗睡了,明天还得上班呢?
END
原文地址:https://www.cnblogs.com/xiaoXuZhi/p/XYH_String2.html