.Net 框架程序设计(5)

1 认识string

     字符串是我们编程中使用最多的类型之一,在C#语言中它作为基元类型。从继承性上来说,string直接继承自object,它是一个引用类型,总是分配在托管堆中,但是它的行为表现的却有着值类型的特性,比如它可以不用new去构建对象,而可以直接赋值的方式;作为函数的引用类型参数,在函数内的操作不会影响到形参等等。

class Program
 {
        static void Main(string[] args)
        {
             public string s = "hello";
             Printing (s);
             Console.WriteLine(s);
         }   

}

public static void Printing(string ss)
{
      ss = "hello world";
      Console.WriteLine(ss);
}


 

     在上面的代码中声明了一个字符串变量s,对变量直接进行了赋值s = "hello",而没有使用创建引用类型的方式s= new string("hello"),我们用ILDasm.exe去查看生成的IL代码,会发现在创建引用类型对象时使用的newobj并没有出现,取而代之的是一个新指令ldstr,它从元数据中获取一个文本常量来构建一个string对象,CLR通过这种方式来优化对string类型的操作。紧接着Printing函数会被调用,它接收一个string对象,按照我们对引用类型变量的理解,Printing函数在内部对string对象的修改会影响外部的string对象,但运行结果并没有像我们想的那样,外部的对象并没有发生变化,而这正好印证了上面所说的string通过特殊的语法去创建对象。在调用Printing函数时如下示意图所示:Printing函数内部发生了如下的变化:

通过对上面的示意图我们不难理解函数的输出。

2 字符串恒定性

      字符串是恒定的,在创建后就不会在变化,这是string一个很重要的特性。考虑如下代码:    

              string s ="hello world";

               Console.WriteLine(s.ToUpper().Substring(1,2));

               Console.WriteLine(s);

在输出的第一行我们对字符串做了一些操作,但是这些操作并没有更改s的值,在第二行的输出中仍然是hello world。在对s的操作中,每次的操作都会创建一个新的string对象,原有的s并没有改变,这就是字符串的恒定性。

        这个特性为string类型带来了一些好处同时也带来了一些性能上的损失,好处是在不用锁定的情况下就可以在多个线程间操作而不用同步;坏处是对字符串的操作产生了大量的临时对象,这些对象会加剧垃圾收集器的收集工作,对性能有一定的影响。

3 字符串的驻留

    因为字符串的恒定性,在作为函数参数或其他一些拷贝操作时都会产生一个全新的副本,这对内存是一个极大的浪费;同时字符串的比较也是一个费时的操作,它要比较字符串中对应位置的每一个字符。为了解决上述的问题,CLR在内部维护一个哈希表,将字符串作为键,将该字符串在托管堆中的引用作为值。当创建一个字符串的时候,CLR会首先在这个哈希表中去查找对应的键是否存在,如果不存在,就创建一个该字符串的副本,把该副本存储在哈希表中,并返回一个该副本的引用;如果存在和创建的字符串相同的键,则直接返回该键对应的值(字符串的引用)。

保存在哈希表中的字符串不受垃圾收集器的管理,也就是说只有在程序域被卸载的时候,这个哈希表才会被释放。

对动态创建的字符串,CLR并没有选择留用,我们可以用string的静态方法Intern来实现强制的留用。如下的代码:

           string s1 = "hello";
            string s2 = "hello";
            bool b = object.ReferenceEquals(s1, s2);
            Console.WriteLine("s1和s2是否具有相同的引用:"+b);
            string s3 = "hello world";
            string s4 = s1 + " world";
            bool b1 = object.ReferenceEquals(s3, s4);
            Console.WriteLine("s3和s4是否具有相同的引用:" + b1);
            Console.WriteLine("s3和s4是否具有相同的值:" + s3.Equals(s4));
            string s5 = string.Intern(s4);
            b1 = object.ReferenceEquals(s3, s5);
            Console.WriteLine("s3和s5是否具有相同的引用:" + b1);


 

输出如下: 

1s2是否具有相同的引用:True

s3s4是否具有相同的引用:False

s3s4是否具有相同的值:True

s3s5是否具有相同的引用:True

 4  字符串池

编译源代码时,文本常量会被嵌入到元数据中,这样就会导致相同的字符串会被多次的嵌入到元数据中,增大了生成模块的容量。为了解决这个问题,C#编译器把字符串写入一次后,在后面的代码中出现相同的,则只是对写入字符串的一个引用,有效保证了生成模块的容量,这就是字符串池技术。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 适合毕业设计、课程设计作业。这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。 所有源码均经过严格测试,可以直接运行,可以放心下载使用。有任何使用问题欢迎随时与博主沟通,第一时间进行解答!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值