.NET中string对象详细解释
一直以为自己对String类用的还算好,今天在cnblogs中看了几篇文章,可谓画龙点精之笔,写的很不错.多多努力和学习吧.
来源:http://www.cnblogs.com/Terrylee/archive/2005/12/26/304876.html
概述
String在任何语言中,都有它的特殊性,在.NET中也是如此。它属于基本数据类型,也是基本数据类型中唯一的引用类型。字符串可以声明为常量,但是它却放在了堆中。希望通过本文能够使大家对.NET中的String有一个深入的了解。
不可改变对象
在.NET中String是不可改变对象,一旦创建了一个String对象并为它赋值,它就不可能再改变,也就是你不可能改变一个字符串的值。这句话初听起来似乎有些不可思议,大家也许马上会想到字符串的连接操作,我们不也可以改变字符串吗?看下面这段代码:
using System;2

3
namespace Demo14


{5

/**//// <summary>6
/// String连接测试7
/// </summary>8
public class Test9

{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在内存中的地址。这样可以确保内存的有效利用。看下面的代码:
using System;2

3
namespace Demo24


{5

/**//// <summary>6
/// String引用类型测试7
/// </summary>8
public class Test9

{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)
using System;2

3
namespace Demo24


{5

/**//// <summary>6
/// String引用类型测试7
/// </summary>8
public class Test9

{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;如果不同再去比较它们的值。所以如果两个值相同的字符串的比较相对于引用相同的字符串的比较要慢,中间多了一步判断引用是否相同。看下面这段代码:
using System;2

3
namespace Demo34


{5

/**//// <summary>6
/// String类型的比较7
/// </summary>8
public class Test9

{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()内部机制完全是一样的,==是它的一个重载。
public static bool operator ==(string a, string b)2


{3
return string.Equals(a, b);4
}5

public 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

字符串驻留
看一下这段代码:
using System;2

3
namespace Demo44


{5

/**//// <summary>6
/// String的驻留7
/// </summary>8
public class Test9

{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对象。但是这两者之间的差别到底有多大呢?来做一个测试:
using System;2
using System.Text;3

4
namespace Demo55


{6

/**//// <summary>7
/// String和StringBulider比较8
/// </summary>9
public class Test10

{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总结:
1)通过上面的分析,可以看出用String来做字符串的连接时效率非常低,但并不是所任何情况下都要用StringBuilder,当我们连接很少的字符串时可以用String,但当做大量的或频繁的字符串连接操作时,就一定要用StringBuilder。
2)String 的值一旦创建就不能再修改,所以称它是恒定的。看似能修改 String 的方法实际上只是返回一个包含修改内容的新 String。如果需要修改字符串对象的实际内容,请使用 System.Text.StringBuilder 类
3)StringBuilder 有一个初始化的内存空间,如果你连接字符串,实际上还是有损失的。损失在于它要申请更大的内存空间。如果你要连接的内容很长,并且知道大概的大小,应该使用StringBuilder sb = new StringBuilder(初始化大小);,减少反复申请内存空间的次数。
浙公网安备 33010602011771号