關於string中涉及到的暫存池

關於string中涉及到的暫存池

之前看了一些string相關的博客,感覺寫的挺好,但終究還是沒深究。哎,學習最怕就是我這種心態了吧!

今天看了一些C#相關的面試題,其中一題感覺很簡單,題目如下:

string a = "abc";
a = (a.ToUpper()+"123").SubString(0,2);

問上述代碼運行時總共會產生多少個臨時對象?

自己看了下,應該是5個:
ToUpper()會產生一個”ABC”,“123”算一個,“ABC”+”123”=”ABC123”又是一個,SubString()也會產生一個(“AB”),再加上a本身的那個,總共是5個。
但是自己想了想,應該如何驗證自己的想法呢?避免出現模棱兩可的情況。所以打算親自驗證下,但是驗證也無法實際驗證,因爲這些都是臨時變量,它們並沒有一個變量來存儲,所以用調試的方式來驗證也是不太可行的。
無奈,只能將上面的代碼改成如下:

        static void Main()
        {
            string a = "abc";
            string b = a.ToUpper();
            string c = "123";
            string d = b + c;
            string e = d.Substring(0, 2);
            string f = "AB";
        }

然後用調試的方法來查看各個字符串變量的內存地址。
本以爲應該會很快解決這個問題,但調試了一遍之後發現不對勁!記得之前看的string相關的博客裏提到過,兩個完全相同的字符串(string對象),他們在C#中引用的會是同一塊內存地址。但上面的調試結果卻讓我傻眼了。變量e和f的值是一樣的,但是它們的地址卻不一樣!這是爲何?

後來又看了下之前的那篇文章:《你真的瞭解.NET中的String嗎?》,發現這篇文章中其實也提到了我遇到的問題,只是沒有明確說明。這對於還是小白的我來說,由於不瞭解C#中String類的暫存池機制,所以之前也是略知一二,知道相同字符串引用的是同一塊內存,但卻忽略了一個嚴重的前提!這個字符串前提是必須在暫存池當中。
而查到這個暫存池主要是因爲看到了String.Intern(string)這個靜態方法。查了下,正好查到了要找的內容:
《囧,對C#駐留池(Intern Pool)機制的誤解》
這裏簡單講解了暫存池,也就是駐留池的一些機制:

  • 駐留池由CLR來維護,其中的所有字符串對象的值都不相同
    駐留池中的所有字符串都不一樣,以此來保證相同字符串的引用地址是相同的。

  • 只有編譯階段的文本字符常量會被自動添加到駐留池,運行時期動態創建的字符串不會被加入到駐留池中
    這也就是爲什麼我上面調試的時候發現e和f的地址不一樣的原因了。這裏也很好理解,因爲f的值在編譯階段就已經確定了的,是靜態的文字常量,而e的值是經過運行產生的,所以e的值不會被存放到Intern Pool中。

  • 可以使用靜態方法String.Intern(string)把動態創建的字符串加入到駐留池中
    要使e和f的引用相同,使用這個方法即可。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章