你真的了解.NET中的String吗?
你真的了解.NET中的String嗎?
Terrylee,2005年12月25日
概述
String在任何語言中,都有它的特殊性,在.NET中也是如此。它屬于基本數(shù)據(jù)類型,也是基本數(shù)據(jù)類型中唯一的引用類型。字符串可以聲明為常量,但是它卻放在了堆中。希望通過本文能夠使大家對(duì).NET中的String有一個(gè)深入的了解。
不可改變對(duì)象
在.NET中String是不可改變對(duì)象,一旦創(chuàng)建了一個(gè)String對(duì)象并為它賦值,它就不可能再改變,也就是你不可能改變一個(gè)字符串的值。這句話初聽起來似乎有些不可思議,大家也許馬上會(huì)想到字符串的連接操作,我們不也可以改變字符串嗎?看下面這段代碼:
?1using?System;
?2
?3namespace?Demo1
?4{
?5????/**<summary>
?6????///?String連接測(cè)試
?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
運(yùn)行的結(jié)果:
1234
12345678
看起來我們似乎已經(jīng)把MyStr的值從“1234”改為了“12345678”。事實(shí)是這樣的嗎?實(shí)際上并沒有改變。在第5行代碼中創(chuàng)建了一個(gè)String對(duì)象它的值是“1234”,MyStr指向了它在內(nèi)存中的地址;第七行代碼中創(chuàng)建了一個(gè)新的String對(duì)象它的值是“12345678”,MyStr指向了新的內(nèi)存地址。這時(shí)在堆中其實(shí)存在著兩個(gè)字符串對(duì)象,盡管我們只引用了它們中的一個(gè),但是字符串“1234”仍然在內(nèi)存中駐留。
引用類型
前面說過String是引用類型,這就是如果我們創(chuàng)建很多個(gè)相同值的字符串對(duì)象,它在內(nèi)存中的指向地址應(yīng)該是一樣的。也就是說,當(dāng)我們創(chuàng)建了字符串對(duì)象a,它的值是“1234”,當(dāng)我們?cè)賱?chuàng)建一個(gè)值為“1234”的字符串對(duì)象b時(shí)它不會(huì)再去分配一塊內(nèi)存空間,而是直接指向了a在內(nèi)存中的地址。這樣可以確保內(nèi)存的有效利用。看下面的代碼:
?1using?System;
?2
?3namespace?Demo2
?4{
?5????/**<summary>
?6????///?String引用類型測(cè)試
?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}
運(yùn)行結(jié)果:
1234
1234
做一個(gè)小改動(dòng),注意Change(ref string s)
?1using?System;
?2
?3namespace?Demo2
?4{
?5????/**?<summary>
?6????///?String引用類型測(cè)試
?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
運(yùn)行結(jié)果:
1234
5678
字符串的比較
在.NET中,對(duì)字符串的比較操作并不僅僅是簡單的比較二者的值,= =操作首先比較兩個(gè)字符串的引用,如果引用相同,就直接返回True;如果不同再去比較它們的值。所以如果兩個(gè)值相同的字符串的比較相對(duì)于引用相同的字符串的比較要慢,中間多了一步判斷引用是否相同。看下面這段代碼:
?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????????????/**測(cè)試引用相同所用的實(shí)際時(shí)間
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????????????/**測(cè)試引用不同而值相同所用的實(shí)際時(shí)間
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
執(zhí)行的結(jié)果(運(yùn)行的結(jié)果可能有些不同):
1671
4172
由此我們看出值相同時(shí)的比較用= =比引用相同時(shí)的比較慢了好多。這里僅僅是一個(gè)測(cè)試,因?yàn)樽鲞@樣的比較并沒有任何實(shí)際的意義。
有一點(diǎn)需要明確的是,.NET中==跟Equals()內(nèi)部機(jī)制完全是一樣的,==是它的一個(gè)重載。
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
執(zhí)行的結(jié)果:
False
True
在這段代碼中,比較這兩個(gè)對(duì)象發(fā)現(xiàn)它的引用并不是一樣的。如果要想是它們的引用相同,可以用Intern()函數(shù)來進(jìn)行字符串的駐留(如果有這樣的值存在)。
StringBuilder對(duì)象
通過上面的分析可以看出,String類型在做字符串的連接操作時(shí),效率是相當(dāng)?shù)偷?#xff0c;并且由于每做一個(gè)連接操作,都會(huì)在內(nèi)存中創(chuàng)建一個(gè)新的對(duì)象,占用了大量的內(nèi)存空間。這樣就引出StringBuilder對(duì)象,StringBuilder對(duì)象在做字符串連接操作時(shí)是在原來的字符串上進(jìn)行修改,改善了性能。這一點(diǎn)我們平時(shí)使用中也許都知道,連接操作頻繁的時(shí)候,使用StringBuilder對(duì)象。但是這兩者之間的差別到底有多大呢?來做一個(gè)測(cè)試:
?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????????????/**測(cè)試String所用的時(shí)間
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????????????/**測(cè)試StringBuilder所用的時(shí)間
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
運(yùn)行結(jié)果:
884
0
通過上面的分析,可以看出用String來做字符串的連接時(shí)效率非常低,但并不是所任何情況下都要用StringBuilder,當(dāng)我們連接很少的字符串時(shí)可以用String,但當(dāng)做大量的或頻繁的字符串連接操作時(shí),就一定要用StringBuilder。
作者:TerryLee
出處:http://terrylee.cnblogs.com/
轉(zhuǎn)載于:https://www.cnblogs.com/SunWentao/archive/2008/04/21/1164193.html
總結(jié)
以上是生活随笔為你收集整理的你真的了解.NET中的String吗?的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: myssh
- 下一篇: ASP.NET_读写Cookie