你真的了解.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吗?的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: myssh
- 下一篇: DIV中class和id的区别