C#拾遗补阙【01】:字符串
一、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#》
C#拾遗补阙【01】:字符串的更多相关文章
- hiho #1326 : 有序01字符串
#1326 : 有序01字符串 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 对于一个01字符串,你每次可以将一个0修改成1,或者将一个1修改成0.那么,你最少需要修改 ...
- 深度优先搜索 codevs 1065 01字符串
codevs 1065 01字符串 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 黄金 Gold 题目描述 Description 输出仅有0和1组成的长度为n的字符串,并且 ...
- Codevs 1065 01字符串
1065 01字符串 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 黄金 Gold 传送门 题目描述 Description 输出仅有0和1组成的长度为n的字符串,并且其中不能含有 ...
- hiho 有序01字符串 dp
题目1 : 有序01字符串 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 对于一个01字符串,你每次可以将一个0修改成1,或者将一个1修改成0.那么,你最少需要修改多少 ...
- codevs——1065 01字符串
1065 01字符串 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 黄金 Gold 题解 题目描述 Description 输出仅有0和1组成的长度为n的字符串, ...
- NPU 2015年陕西省程序设计竞赛网络预赛(正式赛)F题 和谐的比赛(递推 ||卡特兰数(转化成01字符串))
Description 今天西工大举办了一场比赛总共有m+n人,但是有m人比较懒没带电脑,另外的n个人带了电脑.不幸的是,今天机房的电脑全坏了只能用带的电脑,一台电脑最多两人公用,确保n>=m. ...
- P1071 01字符串的交叉安排
题目描述 你有 \(n(1 \le n \le 10^6)\) 个字符'0' 和 \(m(1 \le m \le 10^6)\) 个字符'1'.你需要使用这些字符拼接成一个01字符串,使得满足如下两个 ...
- SYCOJ#1077、01字符串
题目-01字符串 (shiyancang.cn) 1 #include<bits/stdc++.h> 2 using namespace std; 3 4 int main() 5 { 6 ...
- JS 实现"可读"字符串转换成"二进制的01"字符串
问题起源 看过一个漫画, 两位程序员在办公司交流, 可是说的语言却是010101类似的字符串.周围人很是惊异.计算机的世界,确实是由01组成的.今天突然想实现这个编码转换. 解决思路 学过C语言的都知 ...
- 【codevs1065】01字符串
题目大意:输出仅由 0 和 1 组成的长度为 N 的字符串个数,并且其中不能含有 3 个连续的相同子串. 题解:数据太水,正规解法应该是枚举后缀进行判断. 代码如下 #include <bits ...
随机推荐
- Spring Boot自动配置SpringMVC(二)
Spring Boot自动配置SpringMVC(一) - 池塘里洗澡的鸭子 - 博客园 (cnblogs.com)讲述了关于DispatcherServlet注册到诸如tomcat容器中的自动配置过 ...
- centos7.+系统,mysql主从部署
两台服务器或者两个虚拟机 主库:master IP:192.168.85.152 从库:slave IP:192.168.85.153 关闭主库防火墙或者放行mysql的3306端口, ...
- 解决页面js、css代码样式失效
解决方式 根据地址不同的层级深度,加上对应的 " . . / "(不推荐): 去掉所有的 " . . / ", 在js或css的路径前 加上 " / ...
- 市场竞争白热化,Smartbi Excel分析助力企业提高核心竞争力
近年来,随着企业的数字化转型,数据已经成为企业的重要资产,用来支撑其业务决策.对业务数据进行全方位的分析,及时发现问题,调整经营策略,是企业做大做强的必要手段之一.特别是在市场竞争白热化的行业,更需 ...
- MySQL让人又爱又恨的多表查询
1. 前言 在SQL开发当中,多表联查是绝对绕不开的一种技能.同样的查询结果不同的写法其运行效率也是千差万别. 在实际开发当中,我见过(好像还写过~)不少又长又臭的查询SQL,数据量一上来查个十几分钟 ...
- 2、CPU是怎么实现运算的 ?
我先来了解一下芯片构造,芯片由晶体管组成的.晶体管组成逻辑运算与或非电路. P型半导体的"P"表示正电的意思,取自英文Positive的第一个字母. N型半导体的"N&q ...
- 系统资源监控——联用awk与grep文本处理工具,截取磁盘使用量字段
一.使用到的命令行 1.df : df -h #将磁盘使用量用表的形式呈现. 2.awk: awk '{print $5}' #默认分隔符是空格,$后的数字是指定从第几列开始截取. awk -F [] ...
- python3 使用OpenCV计算滑块拼图验证码缺口位置
前言 滑块拼图验证码的失败难度在于每次图片上缺口位置不一样,需识别图片上拼图的缺口位置,使用python的OpenCV库来识别到 环境准备 pip 安装 opencv-python pip insta ...
- Go基础知识梳理(二)
Go基础知识梳理(二) 简单函数的定义 //有参数有返回值 func sum(a int, b int) int { return a + b } //无返回值 func sum(a int, b i ...
- tp5.0 composer下载phpexcel 实现导出excel 表格
tp5.0 composer下载phpexcel 实现导出excel 表格 1.在下载好的tp5.0 框架里面使用 composer 下载phpexcel 的插件 composer require p ...