C#字符串剖析探析.docx

C#基础知识梳理系列七:字符串摘要字符串是保存文本的System.String类型对象。它跟值类型(如:Int32、Int64等)有着相似的使用方法及表达目的,但它并不是值类型。由于在编程中会大量使用字符串,所以CLR为了提高性能及开发方便,对它进行了特殊处理。这一章,我们来介绍一下字符串的驻留机制、字符串池及字符串的比较等特性。注意,本系列所有测试代码均运行于.NET4.0。第一节字符串的定义(System.String)字符串被定义为System.String类型的对象,既然它是引用类型,那么一个未初始化的对象声明将保留为null,并且它的内存只能在堆上分配。它在内部维护的是字符Char的集合,所以它有一个属性Length来表示Char集合中元数的个数。来看一下String类型的定义:String实际上是继承了System.Object类型,同时还实现了一系列接口,如Ienumberable、ICompareable等,所以字符串提供了对字符集合、比较等相关的操作。尽管它是引用类型,但是编译器不允许使用new根据一个文本常量来创建一个字符串对象,而是必须使用简明的声明语法来声明及初始化,对字符串的初始化值是直接被编译进元数据的。比如如下定义一个字符串变量:stringname1=Jack;IL:.methodpublichidebysigspecialnamertspecialnameinstancevoid.ctor()cilmanaged{//代码大小19(0x13).maxstack8IL_0000:ldarg.0IL_0001:ldstrJackIL_0006:stfldstringConsoleApp.Example07.Code_07::name1IL_000b:ldarg.0IL_000c:callinstancevoid[mscorlib]System.Object::.ctor()IL_0011:nopIL_0012:ret}//endofmethodCode_07::.ctor我们知道,通常对于引用类型创建对象是使用newobj指令,但上面的并没有使用该指令,只是使用ldstr指令加载了字符串“Jack”,从IL_0000-IL_0006可以看到是直接加载“Jack”串赋给变量,这是CLR的一种特殊的构造方式。 第二节字符串的不可变性字符串对象一旦创建,在整个进程的生命周期中是不可变的,无法对其进行加长、缩短、改变等操作,既然它不会变,所以也就不存在线程同步的问题,哪怕是皇天老儿创建的线程都无法对其进行改变。如下代码:stringstr1=Jim;stringstr2=str1;Console.WriteLine(object.ReferenceEquals(str1,str2));//Truestr1+=China;Console.WriteLine(object.ReferenceEquals(str1,str2));//False在第一次调用object.ReferenceEquals方法比较的str1和str2,它们指向的是同一个字符串对象引用,所以结果为true,而str1+=China;的过程是重新创建了一个对象,且把新的对象引用赋给str1,此时str1与str2指向的不是同一个对象引用,所以在第二次调用object.ReferenceEquals方法时返回的是false。无论是使用+=操作符还是其他的对字符串修改的方法,都会引起重新创建字符串对象,并且复制旧的字符串到新的内存区,而不是我们常说的“对XX字符串进行修改”,如果非要说“改变”,那就是对对象引用的改变。对于str1+=China;操作,CLR会执行以下操作:1)开辟新的足够大的临时存储区内存来容纳str1和”China”;2)复制str1串到临时区的开始处;3)复制”China”到临时存储区的结尾处;4) str1丢弃对旧对象的引用;5)为str1再一次分配内存区;6)将临时存储区内的字符值复制到4)新开辟的内存区,将str1指向这个内存区的引用。所以对字符串的连接操作会大大损伤性能。我们在下面会讲到.NET提供的一个专门对付字符串连接的类StringBuilder。 第三节字符串的驻留通过前面的描述,我们已经知道字符串的内存是分配在托管堆上,且它是不可改变的,而在编程中,我们会大量使用字符串,这就会导致不停地创建字符串对象,不停地分配内存,并且很有可能不停地执行垃圾回收,如此以来会大大损伤性能,所以CLR对字符串进行了特殊的优化机制,下面我们来对这些机制及特性进行描述。字符串驻留是CLR提供的一种提高性能的对待字符串的机制,它保证在一个进程内的某个字符串在内存中只分配一次。看以下代码:stringstr1=abc;strin

文档评论(0)

1亿VIP精品文档

相关文档