深入理解.net - 4.你必须知道的String
为什么要单独写string,主要是它太常用了,同时又太特殊了,特殊到CLR对它的处理都和其它对象不一样。简直可以称为VIP用户啊。本文并不是一篇介绍如何使用string的文章,而是旨在阐述string的一些本质特性。
引用类型
首先要明确string对象是引用类型的,具有引用类型一切特征,上篇文章也写了关于引用类型的的一些知识,有兴趣的可以看看。引用类型是创建在堆上的,默认是按值传递的。按这个理论来看string就有一些有意思的现象了。
public static void ChangeStringValue(string tmp)
{
tmp = "bbb";
}
public static void Main(string[] args)
{
string str = "aaa";
ChangeStringValue(str);
Console.WriteLine(str);
}
上面代码基本上会写程序的人都知道输入的结果是:aaa
但是string身为一个引用类型调用ChangeStringValue方法时传递的应该是Main方法中str变量的值(即对象实例的引用)啊,在此强调一点就是引用类型和值类型一样默认都是按值传递的。输出的结果为什么不是 bbb 呢?
答案就是:Immutable
恒定不变的(Immutable)String
MSDN上是这么介绍的:
A String object is called immutable (read-only), because its value cannot be modified after it has been created. Methods that appear to modify a String object actually return a new String object that contains the modification.
大体意思就是说:string对象是不变的或只读的,因为创建之后它的值是不能修改的。表面上修改一个string对象实际上返回的是一个包含了修改内容的新的string对象。
所以呢,每次修改string变量其实都是新建了一个string对象。
将上述代码的简单内存模型所示如下:

so,当我们调用ChangeStringValue方法时,传递的确实是string对象的引用,此时变量tmp和str存储的都是"aaa"字符串的引用,
但是由于string的Immutable特殊性,当我们执行tmp= "bbb"; 时,CLR会先创建了一个新的字符串"bbb",然后将ChangeStringValue方法的参数tmp的值修改成字符串"bbb"的引用了。但Main方法中的变量str的值并没有被改变还是指向字符串"aaa"的。所以输出的结果是:aaa
通常我们使用引用类型时,对引用类型的操作是会直接影响到外部的对象的,但由于Immutable特性,string对象的值是无法修改的,为什么要这么设计呢?这又牵扯出另一个有意思的特性。
字符串的驻留(String Interning)
什么是驻留呢,大牛们讨论了很多我就不卖弄了,引用下Artech大神 《再说String》文章中的一段描述如下:
String的驻留机制实际上是在SystemDomain中进行的。当CLR被加载之后,会在SystemDomain对应的managed heap中创建一个Hash table的数据结构,我们可以称这个Hashtable为Interning table,因为它是被用来保存被驻留的string的,Interning table的Key为string本身,Value为string对象的地址。
当我们的托管程序(无论对于那个AppDomain)需要一个string的时候,CLR首先在这个Hashtable根据这个string的hash code试着在Interning table中找对应的Item。如果成功找到,则直接把对应的引用返回,否则就在SystemDomain对应的managed heap中创建该string,并加入到Interning table中,并把引用返回。所以我们说字符串的驻留是基于整个进程的,是可以跨AppDomain共享的,就是这个道理。
显而易见,lock一个string对象是多么恐怖的事情;大量的字符串拼接也是非常浪费性能的,推荐使用StringBuilder。
总结
string是个引用类型,string Immutable,String Interning,这些都是你必须要知道的。臭不要脸的借用了下大神的书名,致敬下经典。
末尾参考链接吐血推荐一波,绝对看的爽歪歪,相信你会收获到更多。
参考链接
- 《你必须知道的.NET》
- String Class - MSDN
- 字符串的驻留(String Interning)- Artech
- 深入理解string和如何高效地使用string - Artech
- 再说String - Artech
- 关于String的终极解释
深入理解.net - 4.你必须知道的String的更多相关文章
- 【源码分析】你必须知道的string.IsNullOrEmpty && string.IsNullOrWhiteSpace
写在前面 之前自信撸码时踩了一次小坑,代码如下: private static void AppServer_NewMessageReceived(WebSocketSession session, ...
- 必须知道的String知识点
1.String 类型的概述 Java中String就是Unicode字符序列,例如,字符串"Java\u2122"由5个Unicode字符J.a.v.a和 ™ 组成.不像C/C+ ...
- Webservice WCF WebApi 前端数据可视化 前端数据可视化 C# asp.net PhoneGap html5 C# Where 网站分布式开发简介 EntityFramework Core依赖注入上下文方式不同造成内存泄漏了解一下? SQL Server之深入理解STUFF 你必须知道的EntityFramework 6.x和EntityFramework Cor
Webservice WCF WebApi 注明:改编加组合 在.net平台下,有大量的技术让你创建一个HTTP服务,像Web Service,WCF,现在又出了Web API.在.net平台下, ...
- C#刨根究底:《你必须知道的.NET》读书笔记系列
一.此书到底何方神圣? <你必须知道的.NET>来自于微软MVP—王涛(网名:AnyTao,博客园大牛之一,其博客地址为:http://anytao.cnblogs.com/)的最新技术心 ...
- (转)【推荐】初级.NET程序员,你必须知道的EF知识和经验
转自:http://www.cnblogs.com/zhaopei/p/5721789.html [推荐]初级.NET程序员,你必须知道的EF知识和经验 阅读目录 [本文已下咒.先顶后看,会涨 ...
- Apple的App Analytics统计平台你必须知道的Q&A整理与翻译
Apple的App Analytics统计平台你必须知道的Q&A整理与翻译 Apple最近在iTunesConnect里最新发布了App Analytics统计平台,提供了现有友盟统计平台和自 ...
- [你必须知道的.NET] 第八回:品味类型---值类型与引用类型(上)-内存有理
原文地址:http://kb.cnblogs.com/page/42318/ 系列文章导航: [你必须知道的.NET] 开篇有益 [你必须知道的.NET] 第一回:恩怨情仇:is和as [你必须知道的 ...
- [你必须知道的.NET]第三十一回,深入.NET 4.0之,从“新”展望
发布日期:2009.05.22 作者:Anytao © 2009 Anytao.com ,Anytao原创作品,转贴请注明作者和出处. /// <summary> /// 本文开始,将以& ...
- 《jQuery风暴》第2章 必须知道的JavaScript知识
第2章 必须知道的JavaScript知识 JavaScript是jQuery应用的基础,掌握JavaScript这门语言是使用jQuery的基础条件.本章不会全面细致的讲解JavaScript的全部 ...
随机推荐
- Python的time(时间戳与时间字符串互相转化)
strptime("string format")字符串如"20130512000000"格式的 输入处理函数 localtime(float a)时间戳的输入 ...
- 菜鸟玩云计算之廿二: saltstack 配置
菜鸟玩云计算之廿二: saltstack 配置 要求环境: RHEL6.4+ >=Python2.6.6, < Python 3.0 关闭salt-master/minion服务: # ...
- Mac OS X 10.8.4下面XZ Utils(*.tar.xz)压缩解压缩命令工具的安装
主要参考:http://bbs.chinaunix.net/thread-3610738-1-1.html 现在很多找到的软件都是tar.xz的格式的,xz 是一个使用 LZMA压缩算法的无损数据压缩 ...
- Dll的编写 在unity中加载
1. 在VS中新建Dll项目 2.在头文件中对函数进行声明 extern "C" int _declspec(dllexport) testunity(); 3.在源文件中写函数体 ...
- listview中的adapter学习小结
概述 Adapter是数据和UI之间的一个桥梁,在listview,gridview等控件中都会使用到,android给我们提拱了4个adapte供我们使用: BaseAdapter是一个抽象类,继承 ...
- ruby中__FILE__,$FILENAME,$PROGRAM_NAME,$0等类似变量的含义
ruby中有4个类似的变量(常量),他们分别是: __FILE__,$FILENAME,$PROGRAM_NAME,$0 他们分别在代码中表示神马呢?我们用实际的例子说明一下: x.rb #!/usr ...
- css左侧固定宽度右侧自适应
左侧固定宽,右侧自适应屏幕宽: 左右两列,等高布局: 左右两列要求有最小高度,例如:200px;(当内容超出200时,会自动以等高的方式增高) 要求不用JS或CSS行为实现: 仔细分析试题要求,要达到 ...
- java -- 对Map按键排序、按值排序
java -- 对Map按键.按值排序 1.按键排序(sort by key) 直接上代码 ↓ public Map<String, Str ...
- python---内置函数,匿名函数,嵌套函数,高阶函数,序列化
函数简单说明 # 函数即"变量" # 高阶函数 # a.把一个函数名当做实参传给另一个函数(在不修改被装饰函数的源代码的情况下,为其添加功能) # b.返回值中包含函数名(不修改函 ...
- Web安全测试工具小集
从此文开始搬家CSDN的博客 本文内容全部节选自<Ajax Security>第14章内容推荐工具: 模糊黑盒测试工具(Fuzzer): Popular free fuzzers incl ...