C#中string简介
C#中的string是System.String的别名,继承与System.Object。我们可以通过下面的代码查看类型的继承关系。
转到定义可以看到是个class类型,是字符char的集合。string既然是引用类型,为什么不能直接通过参数传递在函数中修改呢?
这是因为string类型的不可变性,存储的字符串数值(这里指的是具体的内容常量,而不是对象)是不变的,string对象每次赋值不同的字符串时,都会创建一个新的对象。
我们看一下下面的例子:
可以看到第一次赋值str1和str2引用相同,但是第二次赋值之后引用不同。
在字符串直接赋值时,会把字符串的数值存放在一个缓存池中,当有其他的变量赋予相同的字符串时,是直接引用缓存池中的数值,这样就可以节省存储空间,不需要为每个变量分配相同的字符串空间。
例如上述代码中str1赋值“ab”时,“ab"就存放在缓存池中。当str2得到计算结果时,会从缓存池中查找,发现有相同的字符串,直接赋予引用,所以str1和str2的引用相同,就是True。
第二个为什么变为False了呢?
因为带有变量的操作不会存入缓存池,只有直接常量字符串操作会存在缓存池中。可以用过string.IsInterned查询字符串是否在缓存池中。
static void Main(string[] args) { string str1 = "ab"; string str2 = "a" + "b"; Console.WriteLine("str1={0} (str1==str2)={1} ReferenceEqual={2} IsInterned={3}", str1, str1==str2, object.ReferenceEquals(str1, str2), string.IsInterned(str1)); str1 += "c"; str2 += "c"; Console.WriteLine("str1={0} (str1==str2)={1} ReferenceEqual={2} IsInterned={3}", str1, str1==str2, object.ReferenceEquals(str1, str2), string.IsInterned(str1)); }
可以看出重新赋值后即使str1和str2相等(保存的字符串内容相等),但是引用不相同,“abc”字符串也不在缓存池中。
string常用函数
Compare |
对比两个字符串 |
Equals |
判断两个字符串内容是否相等 |
Format |
字符串格式化 |
IndexOf |
查找第一个匹配到的字符或字符串下标 |
LastIndexOf |
查找最后一个匹配到的字符或字符串下标 |
IsNullOrEmpty |
判断字符串是否为null或"" |
Remove |
删除字符串 |
Replace |
替换字符串 |
Split |
分割字符串 |
Substring |
根据位置获取子串 |
ToCharArray |
字符串转char数组 |
ToLower |
字符串转小写 |
ToUpper |
字符串转大写 |
Trim |
删除头尾空格 |
字符串赋值时如果希望保留转义字符可以使用@符号,例如:
string text = @"This is my blog. \n\t\r ""welcome everybody"""; Console.WriteLine(text);
输出:
This is my blog.
\n\t\r
"welcome everybody"
可以使用$符号进行内插,方便字符串格式化,例如:
string owner = "my"; string text = $"This is {owner} blog. 1+1={1 + 1} Time:{DateTime.Now}"; Console.WriteLine(text);
输出:This is my blog. 1+1=2 Time:2022/4/21 1:08:38
如果频繁的操作字符串,可以考虑使用StringBuilder进行优化。
StringBuilder sb = new StringBuilder("StringBuilder."); sb.Append("Append text."); Console.WriteLine("length={0} capacity={1} string={2}",sb.Length, sb.Capacity, sb.ToString()); sb.Insert("StringBuilder.".Length, "Insert text."); Console.WriteLine("length={0} capacity={1} string={2}", sb.Length, sb.Capacity, sb.ToString()); sb.Replace("Append text.", "Replace text."); Console.WriteLine("length={0} capacity={1} string={2}", sb.Length, sb.Capacity, sb.ToString()); sb = sb.Remove(0, "StringBuilder.".Length); Console.WriteLine("length={0} capacity={1} string={2}", sb.Length, sb.Capacity, sb.ToString()); sb.Length = 6; Console.WriteLine("length={0} capacity={1} string={2}", sb.Length, sb.Capacity, sb.ToString());
输出
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)