在.Net中,string類型的對(duì)象一旦創(chuàng)建即不可修改
string是一種很特殊的數(shù)據(jù)類型,它是引用類型,卻經(jīng)常表現(xiàn)出值類型的特性。在編譯以及運(yùn)行時(shí),.Net都對(duì)它做了一些優(yōu)化工作,正式這些優(yōu)化工作有時(shí)會(huì)迷惑編程人員
1> 字符串恒定
字符串對(duì)象在創(chuàng)建后,盡管從語(yǔ)法上看您似乎可以更改其內(nèi)容,但事實(shí)上并不可行。 例如,編寫此代碼時(shí),編譯器實(shí)際上會(huì)創(chuàng)建一個(gè)新字符串對(duì)象來(lái)保存新的字符序列,且新對(duì)象將賦給 b。 然后字符串“h”將適宜于垃圾回收。
string b = "h"; b += "ello";
2>字符串駐留
我們用以下2行代碼來(lái)說(shuō)明字符串的駐留現(xiàn)象: string a = "str_1"; string b = "str_1"; 請(qǐng)各位同學(xué)友思考一下,這2行代碼會(huì)在內(nèi)存中產(chǎn)生了幾個(gè)string對(duì)象?你可能會(huì)認(rèn)為產(chǎn)生2個(gè):由于聲明了2個(gè)變量,程序第1行會(huì)在內(nèi)存中產(chǎn)生"str_1"供變量a所引用;第2行會(huì)產(chǎn)生新的字符串"str_1"供變量b所引用,然而真的是這樣嗎?我們用ReferenceEquals這個(gè)方法來(lái)看一下變量a與b的內(nèi)存引用地址: string a = "str_1"; string b = "str_1"; Response.Write(ReferenceEquals(a,b)); //比較a與b是否來(lái)自同一內(nèi)存引用 輸出:True 哈,各位同學(xué)看到了嗎,我們用ReferenceEquals方法比較a與b,雖然我們聲明了2個(gè)變量,但它們竟然來(lái)自同一內(nèi)存地址!這說(shuō)明string b = "str_1";根本沒(méi)有在內(nèi)存中產(chǎn)生新的字符串。 這是因?yàn)?,?Net中處理字符串時(shí),有一個(gè)很重要的機(jī)制,叫做字符串駐留機(jī)制。由于string是編程中用到的頻率較高的一種類型,CLR對(duì)相同的字符串,只分配一次內(nèi)存。CLR內(nèi)部維護(hù)著一塊特殊的數(shù)據(jù)結(jié)構(gòu),我們叫它字符串池,可以把它理解成是一個(gè)HashTable,這個(gè)HashTable維護(hù)著程序中用到的一部分字符串,HashTable的Key是字符串的值,而Value則是字符串的內(nèi)存地址。一般情況下,程序中如果創(chuàng)建一個(gè)string類型的變量,CLR會(huì)首先在HashTable遍歷具有相同Hash Code的字符串,如果找到,則直接把該字符串的地址返回給相應(yīng)的變量,如果沒(méi)有才會(huì)在內(nèi)存中新建一個(gè)字符串對(duì)象。 所以,這2行代碼只在內(nèi)存中產(chǎn)生了1個(gè)string對(duì)象,變量b與a共享了內(nèi)存中的"str_1"。
總結(jié):
string a = "str_1"; //聲明變量a,將變量a的指針指向內(nèi)存中新產(chǎn)生的"str_1"的地址 a = "str_2"; //CLR先會(huì)在字符串池中遍歷"str_2"是否已存在,如果沒(méi)有,則新建"str_2",并修改變量a的指針,指向"str_2"內(nèi)存地址,"str_1"保持不變。(字符串恒定) string c = "str_2"; //CLR先會(huì)在字符串池中遍歷"str_2"是否已存在,如果存在,則直接將變量c的指針指向"str_2"的地址。(字符串駐留)
更多請(qǐng)參考:
|