前言
嗨,大家好!
今天咱们来聊一聊一个看似简单却充满玄机的话题 —— String 类型。
字符串应该是所有编程语言中使用最频繁的一种基础数据类型。
在 C# 中,String
可谓是特别的存在:它是引用类型,存储在托管堆中,但在应用上,它却表现得像是值类型。
这个看似简单的类型,背后可藏着许多小秘密呢!准备好一探究竟了吗?
几个问题
作为一名 .NET 程序员,你一定和 String
打过不少交道,在正式分享之前,咱们来做个小测验,考考你的 String
知识,看看你对这个常用类型了解多少:
-
下面这行代码一共创建了几个字符串对象?为什么?
String str = new String("abc");
-
下面两行代码,哪个性能高?为什么?
string str1 = "str1" + 9; string str2 = "str2" + 9.ToString();
-
在下面这两种字符串拼接方式中,哪一种效率更高?为什么?
static void test1() { string a = "t"; a += "e"; a += "s"; a += "t"; } static void test2() { string a = "t"; string b = "e"; string c = "s"; string d = "t"; string result = a + b + c + d; }
能回答上来吗?不能也没关系,跟我继续往下看吧!
创建 String 的 6 种方式
在 C# 中创建字符串其实挺简单的,但不同的创建方式背后有着不同的性能影响。
下面是 6 种常用的创建方法,看看你熟悉哪些!
-
字面量创建:
string str = "Hello, World!";
评价:这是最常见也是最简单的方式,直接用双引号包起来就是字符串,你不需要做额外的操作,简单直接!
-
使用 new 关键字:
String str = new String("Hello, World!");
评价:理论上你可以使用
new
来创建字符串对象,但这样做并不推荐,除非你有特殊的理由,因为字符串是不可变的,这样做至少会创建 2 个字符串对象,反而带来额外的性能开销 -
字符数组拼接:
char[] chars = { 'H', 'e', 'l', 'l', 'o' }; string str = new string(chars);
评价:这个方法在实际使用中不太常见,了解一下就好,但却能让你明白字符串的本质其实是一个字符数组
-
字符串拼接:
string name = "World"; string str = "Hello" + ", " + name + "!";
评价:使用加号(
+
)来拼接字符串,这是另一种常见的创建方式,但在循环中这样做可能会导致性能问题,因为它每次都会创建一个新的字符串对象,适合偶尔使用,频繁使用建议换成StringBuilder
。除此之外,在拼接要警惕装箱操作带来的额外性能开销。 -
格式化字符串:
string str = string.Format("Hello, {0}!", name);
评价:严格地讲,这也是字符串拼接的一种方式,通过
string.Format()
方法,你可以动态插入变量并格式化输出字符串,更加灵活,性能也更高。 -
插值字符串:
string str = $"Hello, {name}!";
评价:C# 6.0 推出的语法糖,可以直接在字符串内部嵌入变量,语法更加简洁优雅。
String 的本质
什么是 String 呢?
本质上,String 就是一连串的有顺序的 16 位的字符数组,简单地说,就是 char[],所以它也具备数组的一系列特性。
String 的特殊性
String 在使用上太频繁了,所以在实现机制上,CLR 给了它很多特殊的照顾:
-
类型处理特殊:
String 类型是引用类型,存储在托管堆中,但在应用上,String 类型表现为值类型。
-
不可变性:
一旦创建了一个字符串对象,你就不能改变它的内容。
这意味着每次你 “修改” 一个字符串时,实际上是在创建一个新的字符串对象。
这个特性保证了字符串的线程安全性和数据完整性。 -
字符串池:
C# 中有一个叫做字符串池的东西,它会自动管理字符串对象。
如果你创建了一个字符串,而这个字符串已经在池中存在了,那么它就不会再创建一个新的对象,而是直接引用已有的对象。这样可以节省内存空间,提高性能。 -
字符编码:
String
默认使用 UTF-16 编码,这让它能够存储丰富的字符集,包括中文、符号等,便于程序国际化。
如何 “销毁” String?
可以用以下语句来手动 “销毁” String 吗?
string testStr = "Hello, String!";
testStr = null;
答案是不可以,因为字符串是不可变的,也就是说一旦创建,它的内容就不能被更改,当你对字符串进行修改时,实际上是创建了一个新字符串,所以它并不能被手动 “销毁”。
和其它引用类型一样,当没有任何引用指向一个字符串对象时,垃圾回收器(GC)会在适当的时候回收它占用的内存。
也就是说,字符串的生命周期由引用它的对象来决定。
使用建议
-
尽量使用字面量创建:
这通常是最简洁和高效的。
-
避免频繁拼接:
在循环或大量拼接操作中,尽量避免使用
+
来拼接字符串,改用StringBuilder
提高性能。 -
利用字符串池:
如果你知道字符串的内容不会改变,可以使用
string.Intern()
方法来尝试获取字符串池中的引用,这样可以提高性能。 -
字符串比较:
在比较字符串时,使用
.Equals()
方法来确保正确性,避免使用==
运算符,因为==
比较的是引用是否相同,.Equals()
方法才是比较字符串的内容。 -
常量字符串:
对于不会改变的字符串,建议定义为常量或只读字段,以提示其他程序员不要修改它们。
-
空字符串检查:
推荐使用
string.IsNullOrEmpty(str)
或string.IsNullOrWhiteSpace(str)
方法来判断字符串是否为空,这样可以避免一些潜在的错误和陷阱。
总结
好了,今天的分享就到这里啦!
你找到开始那几个问题的答案了吗?
String
是 C# 中一个非常特殊且强大的类型。
掌握它的创建方式、内存管理规则及其特性,能够让你的代码更加高效、优雅。
希望今天的分享对你有帮助!
最后,喜欢文章欢迎点个【赞与在看】,你的支持是我最大的动力!如果你有更好的想法或建议,欢迎留言讨论!
往期精彩
- 闲话 .NET(7):.NET Core 能淘汰 .NET FrameWork 吗?
- 常用的 4 种 ORM 框架(EF Core,SqlSugar,FreeSql,Dapper)对比总结
我是老杨,一个执着于编程乐趣、至今奋斗在一线的 10年+ 资深研发老鸟,是软件项目管理师,也是快乐的程序猿,持续免费分享全栈实用编程技巧、项目管理经验和职场成长心得,欢迎关注老杨的公众号,和你共同探索代码世界的奥秘!