好久没写文章了,再拿起这本书,学习加分享,乐趣无穷啊。这两天看了写关于字符串的知识,从学写代码的时候开始,我们就基本天天跟String打交道,对它再熟悉不过了。但是仔细看看,还是有一种拨开云雾的感觉,对平日里的一些问题顿然明白了。


一、 string实例化

1. 创建string对象

string str1 = "hello world."; //√

string str2 = new string("hello world"); //×

按照错误提示试一下char[]类型参数发现可以的:

string str2 = new string(new char[] { 'h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd' });//√

2.IL代码

string str1=”hello world”; 对应的IL代码为:

我们知道实例化引用类型时对应的IL代码为newobj,但是通过上图我们发现string类型比较特殊,使用的ldstr(load string)指令来构建对象。

3. 几点说明:

  • String 直接继承自System.Object,它是引用类型,其实例存储在堆上。而且string是密封类,它是不能够被继承的。
  • 换行:提倡使用Envionment.NewLine进行换行而不是转义字符,因为NewLine会根据平台返回相应的字符,及时跨平台也能正常运行。
  • @符号:文件路径或者正则表达式中出现斜线时,为了防止误当做转义字符,可以在字符串前添加@。例如@"D:\CLRviaC#\Demo01"。
  • string和System.String:System.String是.net framework中定义的一个类型,string是C#定义的一个关键字,代表System.String这种类型,可认为是System.String的简写形式。之前一直认为它是基元类型,经IsPrimitive方法验证其实并不是。(多谢Fish Li指正)。
  • ToString()方法:基类System.Object中包含了该方法,一般在具体使用时会重新定义该类。这个方法比较熟悉,就不赘述了。

二、 字符串驻留

1. 字符串的特色之一就是恒定不变,对于字符串的任何操作(如SubString,ToUpper等)其实都是生成了一个新的字符串,原字符串是保留不变的。

我们来看个例子来验证一下是不是这样的:

//①
string str1 = "HelloWorld";
string str2 = "HelloWorld";
Console.WriteLine(ReferenceEquals(str1, str2));
//②
string str3 = "Hello" + "World";
Console.WriteLine(ReferenceEquals(str1, str3));
//③
string str4 = "Hello";
string str5 = "World";
string str6 = str4 + str5;
Console.WriteLine(ReferenceEquals(str1, str6));
//④
str6 = string.Intern(str6);
Console.WriteLine(ReferenceEquals(str1, str6));

运行结果跟之前的预测或许会有些出入,这是因为CLR使用了字符串驻留的技术,它是通过创建一个哈希表来实现的,其中Key是字符串,value是对于托管堆中string对象的引用,每当创建新的字符串实例的时候会先检测哈希表中是否已经存在相同的字符串。

具体到上面例子中:

  • ①根据字符串驻留技术,str1和str2字符串内容完全相同,实际上指向了同一个引用;
  • ②用+连接的字符串文本常量str3,在编译期间就已经完成连接动作,所以str3也和str1指向了同一引用;
  • ③str6是在运行时才将str4和str5连接在一起的,这个过程中创建了多个字符串对象,最终str6和str1指向的不是同一个引用。
  • ④调用了String.Intern(string str)方法(下文介绍),强制使用字符串驻留技术,所以str6和str1指向了同一引用。

2. String类两个访问哈希表的方法:

  • Public static string Intern(string str);

获取string类型对象的哈希码,并在哈希表中检查是否有匹配项,如果存在则返回string对象的引用,如果不存在,则将其副本添加到哈希表中然后返回引用。

  • Public static string IsInterned(string str);

与上面的方法类似,不同的是没有匹配项时会返回Null,而不会自动将字符串添加到哈希表中。

3. 驻留虽有用,使用需谨慎

当有大量的字符串操作时,驻留机制确实能够节省内存,但是我们却不能滥用这个机制。写程序的时候不能一直默认该机制的存在,除非我们显式调用String.Intern方法,避免产生意想不到的错误,因为这个机制其实是可以被编译器禁用的,随着.NET版本的变化,不能保证一直默认启用字符串驻留。而且,字符串驻留机制对性能和内存的提高也不是绝对的,因为字符串驻留的过程本身也是需要时间的。总之,使用的时候还是要谨慎一些。

三、 StringBuilder

String类型字符串是恒定不变的,当进行字符串累加等大量的字符串操作时,会占用大量的内存。此时最好使用System.Text.StringBuilder类型。

1. 构造StringBuilder对象

StringBuilder使用new关键字构造对象,不像String类型那样特殊。它有大概6种构造器,主要是用来分配和初始化StringBuilder对象的状态,主要包括:

  • 字符串最大容量,默认是Int32.MaxValue;
  • 字符数组:char结构构成的数组,负责维护字符串中的字符内容;
  • 容量:指定StringBuilder维护的字符数组的长度,默认为16.当容量不足时,会自动倍增。

2.与String类型配合  

StringBuilder可以通过ToString()方法在堆上创建相应的String对象,其中包含了该时刻在StringBuilder中的字符串内容。还可以通过Append()方法等将字符串再次添加到StringBuilder中。

StringBuilder提供的方法与String不是完全对应的,可以巧妙的利用它们配合完成一些字符串操作。其中ToLower,Trim,EndsWith等方法是String具有的,而Replace等方法又是StringBuilder特有的。

例如:

StringBuilder s = new StringBuilder();
s.AppendFormat("{0} {1}", "Cathy", "Chen").Replace(" ","-");
string s1 = s.ToString().ToUpper();
Console.WriteLine(s1);

CLR via C#(15)--String,熟悉而又陌生的更多相关文章

  1. 2017.11.15 String、StringBuffer、StringBuilder的比较(todo)

    参考来自:http://blog.csdn.net/jeffleo/article/details/52194433 1.速度 一般来说,三者的速度是:StringBuilder > Strin ...

  2. [CLR via C#]15. 枚举类型和位标志

    一.枚举类型 枚举类型(enumerated types)定义了一组"符号名称/值"配对. 例如,以下Color类型定义了一组符号,每个符号都标识一种颜色: internal en ...

  3. 【CLR】奇妙的String

    - 一.背景 1. 以下代码的HashCode是否相同,它们是否是同个对象: var A = "ab" + "c"; var B = "abc&quo ...

  4. 【Java面试题】15 String s="Hello"; s=s+“world!”;这两行代码执行后,原始的String对象中的内容到底变了没有?String与StringBuffer的超详细讲解!!!!!

    1.Java中哪些类是不能被继承的? 不能被继承的是那些用final关键字修饰的类.一般比较基本的类型或防止扩展类无意间破坏原来方法的实现的类型都应该是final的,在java中,System,Str ...

  5. Android探索之ContentProvider熟悉而又陌生的组件

    前言: 总结这篇文章之前我们先来回顾一下Android Sqlite数据库,参考文章:http://www.cnblogs.com/whoislcj/p/5506294.html,Android程序内 ...

  6. LINQ to SQL语句(15)之String

    LINQ to SQL支持以下String方法.但是不同的是默认情况下System.String方法区分大小写.而SQL则不区分大小写. 1.字符串串联(String Concatenation) v ...

  7. String的内存模型,为什么String被设计成不可变的

    String是Java中最常用的类,是不可变的(Immutable), 那么String是如何实现Immutable呢,String为什么要设计成不可变呢? 前言 关于String,收集一波基础,来源 ...

  8. 字符、字符串和文本的处理之String类型

    .Net Framework中处理字符和字符串的主要有以下这么几个类: (1).System.Char类 一基础字符串处理类 (2).System.String类 一处理不可变的字符串(一经创建,字符 ...

  9. LINQ体验(11)——LINQ to SQL语句之Null语义和String/DateTime方法

    在本系列中.主要介绍LINQ to SQL基础的东西,由于LINQ太强大了,它对我们寻常使用不同的数据源有着不同的内容,其包含对于SQL Server 数据库的LINQ to SQL:对于XML 文档 ...

随机推荐

  1. jQuery源码笔记(一):jQuery的整体结构

    jQuery 是一个非常优秀的 JS 库,与 Prototype,YUI,Mootools 等众多的 Js 类库相比,它剑走偏锋,从 web 开发的实用角度出发,抛除了其它 Lib 中一些中看但不实用 ...

  2. [POJ3096]Surprising Strings

    [POJ3096]Surprising Strings 试题描述 The D-pairs of a string of letters are the ordered pairs of letters ...

  3. Android中的“再按一次返回键退出程序”实现

    用户退出应用前给出一个提示是很有必要的,因为可能是用户并不真的想退出,而只是一不小心按下了返回键,大部分应用的做法是在应用退出去前给出一个Dialog,我觉得这样不太友好,用户还得移动手指去按dial ...

  4. 剑指Offer 连续子数组的最大和

    题目描述 HZ偶尔会拿些专业问题来忽悠那些非计算机专业的同学.今天测试组开完会后,他又发话了:在古老的一维模式识别中,常常需要计算连续子向量的最大和,当向量全为正数的时候,问题很好解决.但是,如果向量 ...

  5. JavaScript中var关键字的使用详解

    作用 声明作用:如声明个变量. 语法 ? 1 var c = 1; 省略var 在javascript中,若省略var关键字而直接赋值,那么这个变量为全局变量,哪怕是在function里定义的. ? ...

  6. Android Studio日志工具的使用

    Android Studio的LogCat工具 Verbose:对应Log.v(),这个方法用于打印那些最为琐碎的信息,意义最小的日志信息.是Android日志里面级别最低的一种. Debug:对应L ...

  7. Win7去除桌面残影的方法

    用户升级到Win7系统后使用正常,就是系统桌面会留有残影,怎么样也去不掉,影响用户的使用,那么要如何将这些残影去掉呢?可从计算机属性中进行相关配置. 解决方法 一.在计算机面板上,右键点击“计算机”, ...

  8. centos 6.5 apache配置web应用&防火墙设置(入门级)

    硬件:centos 6.5 服务器 , Dell R420 , 两个网口,一个给公网,一个给内网. 软件:apache 2.2 配置了virtualhost以后,用curl在本地可以访问.但是其他机器 ...

  9. Intellij IDEA + Jrebel

    Jrebel java热部署神器! 如果你没用过这里一句白话说明,就是在修改了class等源文件后无需重启web容器(如Tomcat)直接生效! 找到以后 安装... 然后 激活地址 :http:// ...

  10. 《oracle每日一练》oralce数据库的导入导出

    今天尝试了数据库的导出,直接在命令行里面使用了导出指令: exp uname/pwd@127.0.0.1:1521/orcl  file='xx.dmp' 出现的问题: 直接@tnsnames里面配的 ...