你真的了解.NET中的String吗?
你真的了解.NET中的String吗?
Terrylee,2005年12月25日
概述
String在任何语言中,都有它的特殊性,在.NET中也是如此。它属于基本数据类型,也是基本数据类型中唯一的引用类型。字符串可以声明为常量,但是它却放在了堆中。希望通过本文能够使大家对.NET中的String有一个深入的了解。
不可改变对象
在.NET中String是不可改变对象,一旦创建了一个String对象并为它赋值,它就不可能再改变,也就是你不可能改变一个字符串的值。这句话初听起来似乎有些不可思议,大家也许马上会想到字符串的连接操作,我们不也可以改变字符串吗?看下面这段代码:
1using System;
2
3namespace Demo1
4{
5 /**<summary>
6 /// String连接测试
7 /// </summary>
8 public class Test
9 {
10 public static void Main(string[] args)
11 {
12 string a = "1234";
13 Console.WriteLine(a);
14
15 a += "5678";
16 Console.WriteLine(a);
17 Console.ReadLine();
18 }
19 }
20}
21
运行的结果:
1234
12345678
看起来我们似乎已经把MyStr的值从“1234”改为了“12345678”。事实是这样的吗?实际上并没有改变。在第5行代码中创建了一个String对象它的值是“1234”,MyStr指向了它在内存中的地址;第七行代码中创建了一个新的String对象它的值是“12345678”,MyStr指向了新的内存地址。这时在堆中其实存在着两个字符串对象,尽管我们只引用了它们中的一个,但是字符串“1234”仍然在内存中驻留。
引用类型
前面说过String是引用类型,这就是如果我们创建很多个相同值的字符串对象,它在内存中的指向地址应该是一样的。也就是说,当我们创建了字符串对象a,它的值是“1234”,当我们再创建一个值为“1234”的字符串对象b时它不会再去分配一块内存空间,而是直接指向了a在内存中的地址。这样可以确保内存的有效利用。看下面的代码:
1using System;
2
3namespace Demo2
4{
5 /**<summary>
6 /// String引用类型测试
7 /// </summary>
8 public class Test
9 {
10 public static void Main(string[] args)
11 {
12 string a = "1234";
13
14 Console.WriteLine(a);
15
16 Test.Change(a);
17
18 Console.WriteLine(a);
19 Console.ReadLine();
20 }
21
22 public static void Change(string s)
23 {
24 s = "5678";
25 }
26 }
27}
运行结果:
1234
1234
做一个小改动,注意Change(ref string s)
1using System;
2
3namespace Demo2
4{
5 /** <summary>
6 /// String引用类型测试
7 /// </summary>
8 public class Test
9 {
10 public static void Main(string[] args)
11 {
12 string a = "1234";
13
14 Console.WriteLine(a);
15
16 Test.Change(ref a);
17
18 Console.WriteLine(a);
19 Console.ReadLine();
20 }
21
22 public static void Change(ref string s)
23 {
24 s = "5678";
25 }
26 }
27}
28
运行结果:
1234
5678
字符串的比较
在.NET中,对字符串的比较操作并不仅仅是简单的比较二者的值,= =操作首先比较两个字符串的引用,如果引用相同,就直接返回True;如果不同再去比较它们的值。所以如果两个值相同的字符串的比较相对于引用相同的字符串的比较要慢,中间多了一步判断引用是否相同。看下面这段代码:
1using System;
2
3namespace Demo3
4{
5 /** <summary>
6 /// String类型的比较
7 /// </summary>
8 public class Test
9 {
10 public static void Main(string[] args)
11 {
12 string a = "1234";
13 string b = "1234";
14 string c = "123";
15 c += "4";
16
17 int times = 1000000000;
18 int start,end;
19
20 /**测试引用相同所用的实际时间
21 start = Environment.TickCount;
22 for(int i=0;i<times;i++)
23 {
24 if(a==b)
25 {}
26 }
27 end = Environment.TickCount;
28 Console.WriteLine((end-start));
29
30 /**测试引用不同而值相同所用的实际时间
31 start = Environment.TickCount;
32 for(int i=0;i<times;i++)
33 {
34 if(a==c)
35 {}
36 }
37 end = Environment.TickCount;
38 Console.WriteLine((end-start));
39
40 Console.ReadLine();
41 }
42 }
43}
44
执行的结果(运行的结果可能有些不同):
1671
4172
由此我们看出值相同时的比较用= =比引用相同时的比较慢了好多。这里仅仅是一个测试,因为做这样的比较并没有任何实际的意义。
有一点需要明确的是,.NET中==跟Equals()内部机制完全是一样的,==是它的一个重载。
1public static bool operator ==(string a, string b)
2{
3 return string.Equals(a, b);
4}
5
1public static bool Equals(string a, string b)
2{
3 if (a == b)
4 {
5 return true;
6 }
7 if ((a != null) && (b != null))
8 {
9 return a.Equals(b);
10 }
11 return false;
12}
13
字符串驻留
看一下这段代码:
1using System;
2
3namespace Demo4
4{
5 /**<summary>
6 /// String的驻留
7 /// </summary>
8 public class Test
9 {
10 public static void Main(string[] args)
11 {
12 string a = "1234";
13 string s = "123";
14 s += "4";
15
16 string b = s;
17 string c = String.Intern(s);
18
19 Console.WriteLine((object)a == (object)b);
20 Console.WriteLine((object)a == (object)c);
21 Console.ReadLine();
22 }
23 }
24}
25
执行的结果:
False
True
在这段代码中,比较这两个对象发现它的引用并不是一样的。如果要想是它们的引用相同,可以用Intern()函数来进行字符串的驻留(如果有这样的值存在)。
StringBuilder对象
通过上面的分析可以看出,String类型在做字符串的连接操作时,效率是相当低的,并且由于每做一个连接操作,都会在内存中创建一个新的对象,占用了大量的内存空间。这样就引出StringBuilder对象,StringBuilder对象在做字符串连接操作时是在原来的字符串上进行修改,改善了性能。这一点我们平时使用中也许都知道,连接操作频繁的时候,使用StringBuilder对象。但是这两者之间的差别到底有多大呢?来做一个测试:
1using System;
2using System.Text;
3
4namespace Demo5
5{
6 /**<summary>
7 /// String和StringBulider比较
8 /// </summary>
9 public class Test
10 {
11 public static void Main(string[] args)
12 {
13 string a = "";
14 StringBuilder s = new StringBuilder();
15
16 int times = 10000;
17 int start,end;
18
19 /**测试String所用的时间
20 start = Environment.TickCount;
21 for(int i=0;i<times;i++)
22 {
23 a += i.ToString();
24 }
25 end = Environment.TickCount;
26 Console.WriteLine((end-start));
27
28 /**测试StringBuilder所用的时间
29 start = Environment.TickCount;
30 for(int i=0;i<times;i++)
31 {
32 s.Append(i.ToString());
33 }
34 end = Environment.TickCount;
35 Console.WriteLine((end-start));
36
37 Console.ReadLine();
38 }
39 }
40}
41
运行结果:
884
0
通过上面的分析,可以看出用String来做字符串的连接时效率非常低,但并不是所任何情况下都要用StringBuilder,当我们连接很少的字符串时可以用String,但当做大量的或频繁的字符串连接操作时,就一定要用StringBuilder。
作者:TerryLee
出处:http://terrylee.cnblogs.com/
转载于:https://www.cnblogs.com/SunWentao/archive/2008/04/21/1164193.html
你真的了解.NET中的String吗?相关推荐
- Java 中的 String 真的是不可变的吗
转载自 Java 中的 String 真的是不可变的吗 我们都知道 Java 中的 String 类的设计是不可变的,来看下 String 类的源码. public final class Str ...
- C++/C++11中std::string用法汇总
C++/C++11中std::string是个模板类,它是一个标准库.使用string类型必须首先包含<string>头文件.作为标准库的一部分,string定义在命名空间std中. st ...
- String和C#中的string有什么区别?
示例( 注意情况 ): string s = "Hello world!"; String s = "Hello world!"; 每种使用的准则是什么? 有什 ...
- 你真的了解Java中的三目运算符吗
转载自 你真的了解Java中的三目运算符吗 三目运算符是我们经常在代码中使用的,a= (b==null?0:1);这样一行代码可以代替一个if-else,可以使代码变得清爽易读. 但是,三目运算符也是 ...
- [转载] Java内存管理-你真的理解Java中的数据类型吗(十)
参考链接: Java中的字符串类String 1 做一个积极的人 编码.改bug.提升自己 我有一个乐园,面向编程,春暖花开! 推荐阅读 第一季 0.Java的线程安全.单例模式.JVM内存结构等知识 ...
- Java中的String为什么是不可变的? -- String源码分析
什么是不可变对象? 众所周知, 在Java中, String类是不可变的.那么到底什么是不可变的对象呢? 可以这样认为:如果一个对象,在它创建完成之后,不能再改变它的状态,那么这个对象就是不可变的.不 ...
- python中string是什么意思_什么是Python中的String:您需要知道的一切
本文将告诉您什么是Python中的string,并向您简要介绍了解该概念的所有细节.本文将介绍以下指针,如何创建字符串?如何从字符串访问字符?格式化字符串,让我们开始,然后,什么 本文将告诉您什么是P ...
- 你真的了解C#中的值和引用吗?(上)
术语解释 在阅读本文之前,你需要了解以下这几个术语是不同的:值.引用.值类型.引用类型. C#中有三种值(value),分别是值类型实例的值.引用类型实例的值和引用. 值类型表达式的值是数据本身. 引 ...
- Java中的String,StringBuilder,StringBuffer三者的区别
最近在学习Java的时候,遇到了这样一个问题,就是String,StringBuilder以及StringBuffer这三个类之间有什么区别呢,自己从网上搜索了一些资料,有所了解了之后在这里整理一下, ...
最新文章
- 利用python读取txt文档的方法_利用Python读取txt文档的方法讲解
- mongodb mysql 事务_MongoDB数据库两阶段提交实现事务的方法详解 _ 蚂蚁视界
- 科普 | USB 协议与接口
- 分享MYSQL中的各种高可用技术(源自姜承尧大牛)
- 漫步最优化三十九——Fletcher-Reeves法
- java 获取键盘点击_Java中获取键盘输入值的三种方法介绍
- win7 mysql zip包如何安装_MySql 5.7.31 win7 Zip压缩包配置教程
- CCS简介及其下载安装卸载
- linux上的MySQL默认端口,linux下mysql 查看默认端口号与修改端口号方法
- 新概念模拟电路_第一册_晶体管_读书笔记
- 优秀课程案例:使用Scratch制作水果忍者游戏!
- Asuswrt RT-AC68U 华硕路由器文件删除漏洞 栈溢出
- python中常用英语口语_常用英语口语100句(超实用)_
- 使用递归顺序和逆序输出单链表
- 春运赶火车小心这些骗术
- 逻辑代数基本公式及定律
- 图解HTTP-阅读笔记
- 基于token身份认证的完整实例
- 三国志战略版:Daniel_S7赤壁之战前瞻2_细节爆料
- 合肥计算机学校 吕子立,合肥理工学校校长张良平一行到皖北经济技术学校考察调研...
热门文章
- BLAS+BLACS+LAPACK+SCALAPACK安装
- Eigen入门之密集矩阵 9 - 别名混乱Aliasing
- angular 使用data-bs-datepicker时的一个小问题及解决
- 【语义分割】Fully Attentional Network for Semantic Segmentation
- python3(六)监督学习
- python 数据科学书籍_您必须在2020年阅读的数据科学书籍
- 香港印象:维多利亚港湾·张学友的手印
- Perl split字符串分割函数用法指南
- Java入门, 线程
- js粘贴板为什么获取不到图片信息_图床+typora,告别markdown中关于图片的困惑