大战熟女丰满人妻av-荡女精品导航-岛国aaaa级午夜福利片-岛国av动作片在线观看-岛国av无码免费无禁网站-岛国大片激情做爰视频

專注Java教育14年 全國咨詢/投訴熱線:400-8080-105
動力節點LOGO圖
始于2009,口口相傳的Java黃埔軍校
首頁 hot資訊 實例講解字符串駐留機制

實例講解字符串駐留機制

更新時間:2020-10-30 17:40:02 來源:動力節點 瀏覽1183次

字符串駐留是一種僅保存一份相同且不可變字符串的方法。字符串駐留機制,其實就是系統維護interned字典,記錄已被駐留的字符串對象。


下面我們通過實際例子探討字符串駐留機制:

Code Snip:

static void Main(string[] args)

{

string str1 = "ABCD1234";

string str2 = "ABCD1234";

string str3 = "ABCD";

string str4 = "1234";

string str5 = "ABCD" + "1234";

string str6 = "ABCD" + str4;

string str7 = str3 + str4;

Console.WriteLine("string str1 = \"ABCD1234\";");

Console.WriteLine("string str2 = \"ABCD1234\";");

Console.WriteLine("string str3 = \"ABCD\";");

Console.WriteLine("string str4 = \"1234\";");

Console.WriteLine("string str5 = \"ABCD\" + \"1234\";");

Console.WriteLine("string str6 = \"ABCD\" + str4;");

Console.WriteLine("string str7 = str3 + str4;");

Console.WriteLine("\nobject.ReferenceEquals(str1, str2) = {0}", object.ReferenceEquals(str1, str2));

Console.WriteLine("object.ReferenceEquals(str1, \"ABCD1234\") = {0}", object.ReferenceEquals(str1, "ABCD1234"));

Console.WriteLine("\nobject.ReferenceEquals(str1, str5) = {0}", object.ReferenceEquals(str1, str5));

Console.WriteLine("object.ReferenceEquals(str1, str6) = {0}", object.ReferenceEquals(str1, str6));

Console.WriteLine("object.ReferenceEquals(str1, str7) = {0}", object.ReferenceEquals(str1, str7));

Console.WriteLine("\nobject.ReferenceEquals(str1, string.Intern(str6)) = {0}", object.ReferenceEquals(str1, string.Intern(str6)));

Console.WriteLine("object.ReferenceEquals(str1, string.Intern(str7)) = {0}", object.ReferenceEquals(str1, string.Intern(str7)));

}

下邊是輸出的結果:

image.png


接下來我們來逐句地分析這段代碼:

首先我們創建了兩個完全相同的字符串(ABCD1234),并將他們分別賦予了兩個字符創變量——str1和str2。然后把它們傳給了object.ReferenceEquals。我們知道object.ReferenceEquals是用于確定兩個變量是否具有相同的引用——換句話說,當兩個變量引用的是同一塊托管推的內存快的時候,返回True,否則返回False。

string str1 = "ABCD1234";

string str2 = "ABCD1234";

object.ReferenceEquals(str1, str2)= True;

object.ReferenceEquals(str1, "ABCD1234")) = True;

令我們感到奇怪的是,當我們分別創建的引用類型兩個變量——string是引用類型。照理說CLR會在托管堆(Managed Heap)中為它們分配兩段內存快,他們不可能具有相同的引用才對,但是為什么object.ReferenceEquals 方法會返回True呢。而對于第二個比較——一個字符串變量和一個和他具有相同內容的字符串("ABCD1234";)直接進行比較,按照我們對CLR內存的分配的一般理解,應該是CLR首先會在托管堆中為這段字符串("ABCD1234")分配內存快,然后把相對應的引用傳遞給object.ReferenceEquals方法(由于分配在托管堆的這段字符串并沒有被任何變量引用,所以當垃圾回收的時候會被回收掉),所以無論如何也不應該返回True。

我們先把問題留到最后,接著分析我們的Sample。上面們對字符串變量之間以及變量與字符串之間進行了比較,如果我們對一個字符串變量和一個動態創建的字符串(通過+Operator把兩個字符串連接起來)進行比較,結果又會如何呢?我們來看看下面的偽代碼演示:

string str3 = "ABCD";

string str4 = "1234";

string str5 = "ABCD" + "1234";

string str6 = "ABCD" + str4;

string str7 = str3 + str4;

object.ReferenceEquals(str1, str5) = True

object.ReferenceEquals(str1, str6) = False

object.ReferenceEquals(str1, str7)) = False

在上面的例子中,我們用三種不同的方式創建了3個字符串變量(str5,str6,str7)——string+string;string+variable;variable+variable。然后分別和我們已經創建的、和它們具有相同字符串“值”的變量(str1)作比較。同樣令我們感到奇怪的是第一個返回True,而后兩個則為False。帶著這些疑惑我們來看看對于string這一特殊的類型說采用的特殊的使用機制。


1.System.String雖然是一個引用類型,但是它具有其自身的特殊性。我們最容易想到的是它創建的特殊性——一般的對象在創建的時候需要通過new關鍵字調用對應的構造函數來實現;而創建一段string不需要這么做——我們只需要把對應的字符換賦給給對應的字符串變量就可以了。之所以存在著這種差異,是因為他們在創建過程中使用的IL指令時不同的——一般的引用對象的創建是通過newobj這樣一個IL指令來實現的,而創建一個字符串變量的IL指令則是ldstr (load string)。(象C#,VB.NET這樣的語言畢竟是高級語言,進行了高度的抽象,站在這樣的角度分析問題往往不能夠看到其實質,所以有時候我們把應該從交底層上面找突破口——比如分析IL,Metadata…);


2. 由于String是我們做到頻率最高的一種類型,CLR考慮性能的提升和內存節約上,對于相同的字符串,一般不會為他們分別分配內存塊,相反地,他們會共享一塊內存。CLR實際上采用這個的機制來實現的:CLR內部維護著一塊特殊的數據結構——我們可以把它看成是一個Hash table,這個Hash table維護者大部分創建的string(我這里沒有說全部,因為有特例)。這個Hash table的Key對應的相應的string本身,而Value則是分配給這個string的內存塊的引用。當CLR初始化的時候創建這個Hash table。一般地,在程序運行過程中,如果需要的創建一個string,CLR會根據這個string的Hash Code試著在Hash table中找這個相同的string,如果找到,則直接把找到的string的地址賦給相應的變量,如果沒有則在托管堆中創建一個string,CLR會先在managed heap中創建該strng,并在Hash table中創建一個Key-Value Pair——Key為這個string本身,Value位這個新創建的string的內存地址,這個地址最重被賦給響應的變量。這樣我們就能解釋上面的疑問了。

string str1 = "ABCD1234";

string str2 = "ABCD1234";

object.ReferenceEquals(str1, str2)= True;

object.ReferenceEquals(str1, "ABCD1234")) = True;

當創建str1的時候,CLR現在我們上面提到的Hash table中找“ABCD1234”這樣的一個string,沒有找到,則在托管堆中為這個string分配一塊內存,然后在Hash table為該string添加一個Key-Value Pair。接著創建str2,CLR仍然會在Hash table找ABCD1234這樣的一個string,這回它會找到我們新創建的這個Entry,所以這個Key-Value Pair中Value(string的地址)會賦給str2。因為str1和str2 具有相同的引用,所以調用object.ReferenceEquals返回True。同理當我們對str1和"ABCD1234"進行比較的時候,str1直接傳入該方法,放傳入"ABCD1234"這個字符串的時候,CLR同樣會在Hash table找ABCD1234這樣的一個string,相同的Entry被找到,這個Entry(Key-Value Pair)的Value(string的地址)被傳到object.ReferenceEquals,所以他們仍然相同的引用,結果返回True。


3. 并非所有的情況下字符串的駐留都會起作用。對于對一個動態創建的字符串(比如string+variable;variable+variable),這種駐留機制便不會起作用。因為對于這樣的字符串,是不會被添加到內部的Hash table中的。但是對于string+string則不同,因為當這樣的語句被編譯成IL的時候,編譯器是先把結構計算出來,然后再調用ldstr指令——而對于string+variable;variable+variable這種情況,所對應的IL指令是Concat。所以對于string+string字符串的駐留仍然有效。

比如對于以下一段代碼:

static void Main(string[] args)

{

string str1 = "ABC";

string str2 = str1 + "123";

string str3 = "ABC" + "123";

}

對應的IL Code是:

.method private hidebysig static void Main(string[] args) cil managed

{

.entrypoint

// Code size 26 (0x1a)

.maxstack 2

.locals init ([0] string str1,

[1] string str2,

[2] string str3)

IL_0000: nop

IL_0001: ldstr "ABC"

IL_0006: stloc.0

IL_0007: ldloc.0

IL_0008: ldstr "123"

IL_000d: call string [mscorlib]System.String::Concat(string,

string)

IL_0012: stloc.1

IL_0013: ldstr "ABC123"

IL_0018: stloc.2

IL_0019: ret

} // end of method Program::Main


所以現在我們就可以解釋第二個疑問了。

雖然對于對一個動態創建的字符串(比如string+variable;variable+variable),字符串駐留機制便不會起作用。但是我們可以手工的啟用駐留機制——那就是調用定義的System.String中的靜態方法Intern。這個方法接受一個字符串作為他的輸入參數,返回的經過駐留處理的string。他的實現機制是:如果能在內部的Hash Table中找到傳入的string,則返回對應的string引用,否則就在Hash Table添加該string對應的Entry,并返回string的引用。


以上就是對字符串駐留機制的講解,通過一步一步的分析我們知道了字符串駐留機制的本質。字符串駐留機制只是字符串里面很小的一個知識點,在本站的Java基礎教程里面還有更多的字符串的相關知識等你來學!


提交申請后,顧問老師會電話與您溝通安排學習

免費課程推薦 >>
技術文檔推薦 >>
主站蜘蛛池模板: 亚洲国产欧洲综合997久久 | 特黄特级高清免费视频毛片 | 日韩黄色大片免费看 | 国产性videostv另类极品 | 日本中文字幕永久在线 | 欧美在线观看一区二区三 | 久久99热久久精品动漫 | 亚洲一区二区影院 | 99热这里只有精品18 | 久久精品国产福利国产秒 | 黄视频网站免费看 | 亚洲性图第一页 | 亚洲国产中文在线 | 99r在线精品| 欧美日韩一区二区三区麻豆 | 高清国产美女一级毛片 | 国产99久9在线视频 国产99久久 | 久久成人激情视频 | 五月婷婷六月综合 | 国产玖玖视频 | 久久九九爱 | 麻豆国产在线观看一区二区 | 亚洲国产婷婷综合在线精品 | 天天摸天天操天天射 | 四虎影视成人永久在线播放 | 久久精品免视看国产明星 | 久久草视频在线 | 女人18毛片特级一级免费视频 | 国产91小视频在线观看 | 国产高清一区二区三区 | 欧美激情亚洲精品日韩1区2区 | 久久成人国产 | 久久香蕉国产线看观看乱码 | 免费观看黄色a一级录像 | 久久se精品一区二区影院 | youjizz欧美粗又大中国 | 中文字幕在线精品视频入口一区 | 激情在线播放免费视频高清 | 中文字幕视频一区 | 伊人久久精品亚洲精品一区 | 99re这里只有热视频 |