一、string是特殊的引用类型

​ 众所周知,string是引用类型。为什么string是引用类型,最简单的方法,f12转到string的定义。显而易见,string的本质是类,字符串存储在堆中,而string作为关键字,是String的别名。

​ 然而,实例一个string对象不需要使用 new 关键字,而是直接使用字面值字符串,如:

string str= "Hello";
Console.WriteLine(str);
Console.ReadKey();

​ 用ILSpy查看上述的代码IL,未出现预期的IL指令newobj,只有一个特殊的ldstr指令,CLR使用一种特殊的方式构造string对象。

​ 当然,String类也提供了不同的构造函数,可使用new构造字符串,如:



​ 试着用new构造一个string对象,查看其产生的IL,惊喜的发现new构造的字符串使用IL指令newobj。

string str= new string(new char[] { 'H', 'e', 'l', 'l', 'o' });

二、string是不可变的

​ string对象最为重要的一个特征:字符串一旦创建便是恒定不变,字符串一经创建便不能更改,不能边长、变短或修改字符。string对象发生修改时,实际上不会改变原来的值,而是在托管堆中重新创建一个新的字符串,将新的引用地址传递给string对象,如下图代码和托管堆变化示例

string str= "Hello";
str = "你好";

​ 由上图可知,每次对字符串进行操作,都需要在托管堆中重新分配一个新的空间地址来存储字符串,如果频繁操作某一个string对象字符串,会在堆上创建大量的对象,从而影响性能。如果需要频繁操作字符串,推荐使用StringBuilder。下面是string和StringBuilder简单的对比:

string str= string.Empty;
Stopwatch watch = new Stopwatch();
watch.Start();
for (int i = 0; i < 10000; i++)
{
str += "Hello World";
} watch.Stop();
Console.WriteLine(watch.Elapsed); watch.Restart();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 10000; i++)
{
sb.Append("Hello World");
} watch.Stop();
Console.WriteLine(watch.Elapsed);

三、字符串驻留

​ ​ 字符串是我们十分频繁使用的类型,由于字符串是不可变的特性,会创造大量的对象,因而有了字符串驻留。先看看下面的例子:

string str1 = "Hello";
string str2 = "Hello";
Console.WriteLine(object.ReferenceEquals(str1,str2));

输出:True。也就是说,str1和str2这两个string对象都引用了同一个内存地址

接下来继续拓展示例:

string str1 = "Hello";
string str2 = "Hello";
string str3 = " LiMing";
string str4 = "Hello LiMing";
string str5 = "Hello" + " LiMing";
string str6 = str3 + " LiMing"; ;
string str7 = str3 + str4; Console.WriteLine(object.ReferenceEquals(str1,str2));
Console.WriteLine(object.ReferenceEquals(str4, str5));
Console.WriteLine(object.ReferenceEquals(str4, str6));
Console.WriteLine(object.ReferenceEquals(str4, str7));

​ 从上面的例子不难发现,并不是所有相等的字符串的地址都是一样的。实际上,在CLR内部维护了一个哈希表,在这个哈希表中,key时字符串,value是托管堆中的地址。在程序运行中,CLR将字面值(形如str1)的字符串,都会通过驻留机制,将这些字符串进行维护到哈希表中。当s创建str1时,会先判断是否在哈希表中有相同的字符串,如果没有,则创建一个新的对象;当创建str2时,哈希表中已经有相同的字符串时,直接返回已有的引用地址给str2。那为什么str6、str7的引用地址和str4不相同呢?因为str6、str7是动态字符串,即非字面值的字符串。

《CLR Via C#》

字符串的驻留(String Interning) - Artech - 博客园 (cnblogs.com)

最新文章

  1. OpneCv2.x 模块结构
  2. spring源码分析之spring jmx
  3. 图结构练习——最短路径(dijkstra算法(迪杰斯拉特))
  4. 【BZOJ】2924: [Poi1998]Flat broken lines
  5. python 学习笔记十一 SQLALchemy ORM(进阶篇)
  6. Effective Java 13 Minimize the accessibility of classes and members
  7. 利用text插件和css插件优化web应用
  8. html--offsetLeft,Left,clientLeft的关键--动态获取计算元素位置关系
  9. 移动App双周版本迭代实战--转载备用
  10. MySQL sql 执行步骤
  11. jenkins 杀死衍生进程
  12. Flink从入门到放弃(入门篇1)-Flink是什么
  13. 转---Google Python编程风格指南
  14. python-turtle 快给你的爷爷看看啥是 “小猪佩奇”
  15. Server SQL Modes
  16. Nan-boxing技术介绍
  17. San初步使用
  18. ThreadPoolExecutor类
  19. golang sizeof 占用空间大小
  20. java并发之同步辅助类CyclicBarrier和CountDownLatch

热门文章

  1. Solution -「LOCAL」「cov. HDU 6864」找朋友
  2. ansible手动添加模块
  3. 终极指南:企业级云原生 PaaS 平台日志分析架构全面解析
  4. SIMD编码/解码
  5. 中国首个进入谷歌编程之夏(GSoC)的开源项目: Casbin, 2022 年预选生招募!
  6. intellij IDEA 安装、简单使用与创建javaWeb项目
  7. 为什么三层架构中业务层(service)、持久层(dao)需要使用一个接口?
  8. Android SugarORM(2)
  9. Web应用程序攻击和检查框架w3af
  10. VS 返回值被忽略的解决方法