一、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)

C#拾遗补阙【01】:字符串的更多相关文章

  1. hiho #1326 : 有序01字符串

    #1326 : 有序01字符串 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 对于一个01字符串,你每次可以将一个0修改成1,或者将一个1修改成0.那么,你最少需要修改 ...

  2. 深度优先搜索 codevs 1065 01字符串

    codevs 1065 01字符串  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 黄金 Gold 题目描述 Description 输出仅有0和1组成的长度为n的字符串,并且 ...

  3. Codevs 1065 01字符串

    1065 01字符串 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 黄金 Gold 传送门 题目描述 Description 输出仅有0和1组成的长度为n的字符串,并且其中不能含有 ...

  4. hiho 有序01字符串 dp

    题目1 : 有序01字符串 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 对于一个01字符串,你每次可以将一个0修改成1,或者将一个1修改成0.那么,你最少需要修改多少 ...

  5. codevs——1065 01字符串

    1065 01字符串  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 黄金 Gold 题解       题目描述 Description 输出仅有0和1组成的长度为n的字符串, ...

  6. NPU 2015年陕西省程序设计竞赛网络预赛(正式赛)F题 和谐的比赛(递推 ||卡特兰数(转化成01字符串))

    Description 今天西工大举办了一场比赛总共有m+n人,但是有m人比较懒没带电脑,另外的n个人带了电脑.不幸的是,今天机房的电脑全坏了只能用带的电脑,一台电脑最多两人公用,确保n>=m. ...

  7. P1071 01字符串的交叉安排

    题目描述 你有 \(n(1 \le n \le 10^6)\) 个字符'0' 和 \(m(1 \le m \le 10^6)\) 个字符'1'.你需要使用这些字符拼接成一个01字符串,使得满足如下两个 ...

  8. SYCOJ#1077、01字符串

    题目-01字符串 (shiyancang.cn) 1 #include<bits/stdc++.h> 2 using namespace std; 3 4 int main() 5 { 6 ...

  9. JS 实现"可读"字符串转换成"二进制的01"字符串

    问题起源 看过一个漫画, 两位程序员在办公司交流, 可是说的语言却是010101类似的字符串.周围人很是惊异.计算机的世界,确实是由01组成的.今天突然想实现这个编码转换. 解决思路 学过C语言的都知 ...

  10. 【codevs1065】01字符串

    题目大意:输出仅由 0 和 1 组成的长度为 N 的字符串个数,并且其中不能含有 3 个连续的相同子串. 题解:数据太水,正规解法应该是枚举后缀进行判断. 代码如下 #include <bits ...

随机推荐

  1. 看我如何使用 shell 来获取所有 KVM 虚拟机的 IP 地址

    文章目录 脚本说明 脚本展示 效果展示 此脚本的初衷是因为,KVM创建的桥接网卡的虚拟机,无法使用virsh domifaddr命令获取IP,而创建的nat网卡的虚拟机,则可以直接使用virsh do ...

  2. OpenStack、虚拟机以及和当前流行的k8s、Docker四者之间的关系

    一.OpenStack与虚拟机之间的关系 OpenStack使用Python语言开发,是虚拟资源管理工具,他可以协助你搜集各种资源,并加以利用以及管理,实现物理资源的高效使用和安全.虚拟化物理机这个动 ...

  3. 关于 share 音乐分享官方文档补充

    例子 音乐分享 /*--------微信朋友圈--------*/ [shareParams SSDKSetupWeChatParamsByText:@"内容" title:@&q ...

  4. RadonDB MySQL on K8s 2.1.2 发布!

    RadonDB MySQL on Kubernetes 于 2 月 17 日发布了新版本 2.1.2 .该版本在节点的重建.增删等方面进行了全面升级. 致谢: 首先感谢 @andyli029 @ace ...

  5. Bypass BeaconEye - Beacon 堆混淆

    这是[信安成长计划]的第 9 篇文章 关注微信公众号[信安成长计划] 0x00 目录 0x01 CS4.5 Sleep_Mask 0x02 HeapEncrypt 0x03 效果 0x04 参考文章 ...

  6. 浅谈:redis的主从复制 + 哨兵模式

    浅谈:redis的主从复制 + 哨兵模式 主从模式 ​ 在谈论redis的主从复制之前,我们先回想下mysql的主从搭建过程,第一步呢首先要在主库服务器中修改my.cnf,开启一下bin_log功能, ...

  7. 为什么越来越多的企业选择商业智能BI?

    ​在大数据,云计算,工业4.0,物联网等概念概念炒得飞起的年代,现在已经变成某宝天天给我推送我感兴趣的东西.由此可见数据和科技正在慢慢深刻地改变我们的生活. 随着时代的发展,各个企业的内部决策方式也是 ...

  8. Hook(钩子技术)基本知识讲解,原理

    一.什么是HOOK(钩子)  API Windows消息传递机制,当在应用程序进行相关操作,例如点击鼠标.按下键盘,操作窗口等,操作系统能够感知这一事件,接着把此消息放到系统消息队列,然后到应用程序的 ...

  9. 彻底关闭 win10家庭版 杀毒软件windows defender

    下面开始今天的教程, 第一步,我们先在windows安全中心将相关的设置关闭一下,具体方法如下: 我们右键点击windows 10开始菜单,点击"设置", 点击"设置&q ...

  10. 2020.9.28 多进程multiprocess 进程池pool 子进程subprocess 进程间通信

    1.multiprocessing模块--跨平台版本的多进程模块 multiprocessing模块提供了一个Process类来代表一个进程对象,下面的例子演示了启动一个子进程并等待其结束: from ...