艾伟_转载:.NET Discovery 系列之二--string从入门到精通(勘误版下)

简介: 本系列文章导航.NET Discovery 系列之一--string从入门到精通(上).NET Discovery 系列之二--string从入门到精通(勘误版下).NET Discovery 系列之三--深入理解.

本系列文章导航

.NET Discovery 系列之一--string从入门到精通(上)

.NET Discovery 系列之二--string从入门到精通(勘误版下)

.NET Discovery 系列之三--深入理解.NET垃圾收集机制(上)

.NET Discovery 系列之四--深入理解.NET垃圾收集机制(下)

.Net Discovery 系列之五--Me JIT(上)

.NET Discovery 系列之六--Me JIT(下)

.NET Discovery 系列之七--深入理解.NET垃圾收集机制(拾贝篇)

  string可以说是.Net中比较复杂的一种数据类型,很多文章介绍过它,但不是很全面,本文全面的介绍了string的各种内部机制与特性,欢迎点评。本文为修正版,对前文进行了一些勘误,感谢地狱门神、 Anytao、 eaglet 三位网友的帮助!

  前两节我们介绍了string的两个基本特性,如果你觉得你已经比较全面的了解了string,那么就来看看这第3、4两节吧。

  三.有趣的比较操作

  在第一节与第二节中,我们分别介绍了字符串的恒定性与与驻留性,如果这位同学友觉得完全掌握了以上内容,那么就在第三节中检验一下自己的学习成果吧!

  以下10段简单的代码将通过值比较与地址引用比较,来说明前两节讲到的内容,大家也可以通过这些代码来检测一下自己对string的了解程度。

  代码一:

 
 
string a = " str_1 " ;
string b = " str_1 " ;
Response.Write(a.Equals(b));
Response.Write(ReferenceEquals(a,b));

// 输出:True (Equals比较字符串对象的值)
//    True (ReferenceEquals比较字符串对象的引用,由于字符串驻留机制,
// a与b的引用相同)

  代码二:

代码
 
  
string a = " str_1str_2 " ;
string b = " str_1 " ;
string c = " str_2 " ;
string d = b + c;
Response.Write(a.Equals(d));
Response.Write(ReferenceEquals(a, d));

// 输出:True(Equals比较字符串对象的值)
// False(ReferenceEquals比较字符串对象的引用,由于变量d的值为变量连接的结果,
// 字符串驻留机制无效)

  代码三:

代码
 
  
string a = " str_1str_2 " ;
string b = " str_1 " + " str_2 " ;
Response.Write(a.Equals(b));
Response.Write(ReferenceEquals(a, b));
// 输出:True(Equals比较字符串对象的值)
// True (ReferenceEquals比较字符串对象的引用,由于变量b的值为常量连接的结果,字符串驻留机制
有效。如果变量b的值由“常量+变量”的方式得出,则
  字符串驻留无效)

  代码四:

 
 
string a = " str_1 " ;
string b = String.Copy(a);
Response.Write(a.Equals(b));
Response.Write(ReferenceEquals(a, b));

// 输出:True(Equals比较字符串对象的值)
// False (ReferenceEquals比较字符串对象的引用,Copy操作产生了新的string对象)

  代码五:

 
 
string a = " str_1 " ;
string b = String.Copy(a);
b
= String.Intern(b);
Response.Write(a.Equals(b));
Response.Write(ReferenceEquals(a, b));
// 输出:True(Equals比较字符串对象的值)
// True (ReferenceEquals比较字符串对象的引用,String.Intern实现了字符串驻留)

  代码六:

 
 
string a = " str_1 " ;
string b = String.Copy(a);
string c = " str_1 " ;
Response.Write((
object )a == ( object )b);
Response.Write((
object )a == ( object )c);
// 输出:False (“==”在两边为引用类型时,则比较引用的地址,所以a与b为不同引用)
True (ReferenceEquals比较字符串对象的引用,a与c由于字符串驻留机制,引用相同)

  代码七:

 
 
string a = " str_1 " ;
string c = " str_1 " ;
Response.Write(a
== c);
// 输出:True

  刚才我们提到过,“==”在两边为引用类型时,则比较引用的地址;如果是值类型时则需要比较引用和值。string为引用类型,那么上面的代码是比较了变量a与c的地址还是地址和值呢?答案是:比较了地址和值!因为在string类型比较的时候,“==”已经被重载为“Equals”了,所以,虽然你在用“==”比较两个引用类型,但实际上是在用“Equals”比较它们的地址和值!(先比较地址,地址不等再比较值)

  代码八:

 
 
string a = " a " ;
string b = new string ( ' a ' , 1 );
Response.Write(a.Equals(b));
Response.Write(ReferenceEquals(a, b));

// 输出:True (Equals比较值,a与b的值相同)
// False (ReferenceEquals比较字符串对象的引用)

  代码九:

 
 
string a = " a " ;
string b = new string ( ' a ' , 1 );
Response.Write(a.Equals(
string .Intern(b)));
Response.Write(ReferenceEquals(a,
string .Intern(b)));
// 输出:True (Equals比较值,无论是否Intern都会相同)
// True (ReferenceEquals比较字符串对象的引用,Intern已经将b驻留至字符串池内)

  代码十:

 
 
string a = " str " ;
string b = " str_2 " .Substring( 0 , 3 );
Response.Write(a.Equals(b));
// 输出:True (Equals比较值,a与c的值相同)
// False (ReferenceEquals比较字符串对象的引用,Substring操作产生了新的字符串对象)

  此段代码产生了3个string对象,是哪3个呢?如果你不明白,还是从头再看一遍吧!

 

  四.艺海拾贝

  这一节将主要给大家介绍一些string的常见问题。

  1.“string = ”与“new stirng()”的区别

 

 
 
string test = " a " ;
string test = new string ( ' a ' , 1 );

以上两行代码的效果是一样的,它们的区别在于加载”a”的时间不同:第一行的“a”是一个常量,在编译期就已经被放在一个叫做常量池的地方了,常量池通常装载一些在编译期被确定下来的数据,例如类、接口等等;而第二行是运行时CLR在堆中生成的值为“a”的字符串对象,所以后者没有字符串驻留。

 

  2. string 与 String的区别

  String的大名叫做System.String,在编译为IL代码时,string和System.String会生成完全相同的代码:(ps:long和System.Int64,float和System.Single等也有此特性)

 

 
 
string str_test = " test " ;
System.String Str_test
= " test " ;

IL码:

 

 

 
 
// 代码大小 14 (0xe)
.maxstack 1
.locals init ([ 0 ] string str_test,[ 1 ] string Str_test)
IL_0000: nop
IL_0001: ldstr " test "
IL_0006: stloc.0
IL_0007: ldstr " test "
IL_000c: stloc.1
IL_000d: ret

所以,二者的区别并不在于底层,而是在于string是类似于int的基元类型;System. String是框架类库(FCL)的基本类型,二者之间有直接的对应关系。

 

  3.StringBuilder

  StringBuilder提供了高效创建字符串的方法,由StringBuilder表示的字符串是可变的(非恒定的),在需要多处使用“+”连接字符串变量的时候,推荐使用StringBuilder来完成,最后调用其ToString()方法输出。当调用了StringBuilder的ToString()方法之后,StringBuilder将返回其内部维护的一个字符串字段引用,如再次修改StringBuilder,它将会创建一个新的字符串,这时被修改的是新的字符串,原来已经返回的字符串才不会发生改变。

  StringBuilder有两个比较重要的内部字段,大家需要掌握:

  m_MaxCapacity:StringBuilder的最大容量,它规定了最多可以放置到m_StringValue的字符个数,默认值为Int32.MaxValue。m_MaxCapacity一旦被指定就不能再更改。

  m_StringValue:StringBuilder维护的一个字符数组串,实际上可以理解为一个字符串。StringBuilder重写的Tostring()方法返回的就是这个字段。

  讲到这里,你已经掌握了string的大部分秘密,怎么样,你对string应该有全新的认识了吧!

目录
相关文章
|
5月前
|
存储 C++ 容器
C++入门指南:string类文档详细解析(非常经典,建议收藏)
C++入门指南:string类文档详细解析(非常经典,建议收藏)
70 0
|
5月前
|
开发框架 前端开发 .NET
七天.NET 8操作SQLite入门到实战 - (1)第七天BootstrapBlazor UI组件库引入
七天.NET 8操作SQLite入门到实战 - (1)第七天BootstrapBlazor UI组件库引入
|
2月前
|
前端开发 JavaScript 安全
入门Vue+.NET 8 Web Api记录(一)
入门Vue+.NET 8 Web Api记录(一)
81 4
|
5月前
|
开发框架 .NET 中间件
七天.NET 8操作SQLite入门到实战 - (2)第七天Blazor班级管理页面编写和接口对接
七天.NET 8操作SQLite入门到实战 - (2)第七天Blazor班级管理页面编写和接口对接
|
2月前
|
NoSQL 安全 Java
Redis6入门到实战------ 三、常用五大数据类型(字符串 String)
这篇文章深入探讨了Redis中的String数据类型,包括键操作的命令、String类型的命令使用,以及String在Redis中的内部数据结构实现。
Redis6入门到实战------ 三、常用五大数据类型(字符串 String)
|
28天前
|
SQL 关系型数据库 数据库
七天.NET 8操作SQLite入门到实战详细教程(选型、开发、发布、部署)
七天.NET 8操作SQLite入门到实战详细教程(选型、开发、发布、部署)
|
28天前
|
开发框架 .NET Java
C#/.NET/.NET Core自学入门指南
C#/.NET/.NET Core自学入门指南
|
2月前
|
开发框架 前端开发 .NET
七天.NET 8操作SQLite入门到实战 - (3)第七天Blazor学生管理页面编写和接口对接
七天.NET 8操作SQLite入门到实战 - (3)第七天Blazor学生管理页面编写和接口对接
|
4月前
|
存储 IDE C#
C#入门:在JetBrains Rider中创建.Net Framework控制台应用程序,输出“Hello, World!”
C#入门:在JetBrains Rider中创建.Net Framework控制台应用程序,输出“Hello, World!”
391 0
|
5月前
|
存储 NoSQL 安全
Redis入门到通关之Redis数据结构-String篇
Redis入门到通关之Redis数据结构-String篇
86 1