你真的理解正確String某些特性了嗎?
最近在園子里看到幾篇關于string的文章,感覺其中有一些誤解,不知道是自己理解有誤還是園友理解錯誤,也沒發(fā)現(xiàn)有園友提出質疑,索性也將自己的一點理解寫出來,也對一些質疑提出了自己的解釋,不管怎樣我希望如果是我哪里理解錯誤大家一定要提出來,我們一起進步,否則真的會誤導很多人,也感覺到寫文章是要負責任的,否則就干脆寫日志,不要發(fā)表出來誤導到了一些對.Net不熟悉的朋友!
1.在DoNet中String是不可改變的,什么叫不可變呢,首先大家先看下面的例子:
string a = "1"; 而是創(chuàng)建了一個新的字符串; 所以String的不可變就是當你在創(chuàng)建了字符串后其不可修改; |
2.當創(chuàng)建多個字符串內(nèi)容相同的對象時,都只會指向同一個引用;
string a = "11"; |
a和b都指向同一個a的引用,并不會為b重新分配內(nèi)存;這樣即可保證內(nèi)存有效利用;這一點用IL不是很好看出來,所以大家可以按下面方法去比較他們的引用地址,都是指向同一個堆;
Console.WriteLine(string.ReferenceEquals(a, b)); |
運行結果:
True |
3.字符串比較:
==和!=是為了比較String對象的值是否相同而不是比較引用;
例如等號首先是比較引用是否相同,因為引用相同值一定會相同,就避免了再去對值進行比較;
而引用如果不同再去比較值,相同則返回true;
總之==一定一定是為了比較字符串的值是否相同;
string s2 = new StringBuilder().Append("My").Append("Test").ToString(); |
上面是返回False,大家肯定有些迷惑,而此前一位園友則解釋我也不盡贊同,這里只發(fā)表我的解釋:
此處比較的是兩個引用類型,為什么這么說,因為大家都知道引用地址都是存放在棧中,而此處正是將存放在棧中的引用地址裝箱轉換成了引用類型也就是分別創(chuàng)建了兩個值為引用地址的堆,而他們引用地址的值肯定不一樣,所以結果顯然就是False了;
4.為什么總是提倡使用StringBuilder對象;
如果用String,每進行一次字符串的拼接就要分配一個新的堆,如果只有一兩次倒無所謂,如果頻繁如此操作性能會很差;但StringBuilder是在為其分配的堆上做修改,不會重新分配,所以性能比String拼接字符串好;相信大家理解上面幾點了我這里也純粹是廢話了,呵呵!
5.***就是看到有人提到Intern方法,我感覺他們對此方法具體功能理解不透徹存在誤解;
首先看下面例子:
static void Main(string[] args) |
先看***個Main,我根據(jù)***個Main來解釋:
如果傳遞給Intern的是一個變量的引用地址,那么他會檢索是否用與此引用地址所指向的堆的值相同的其他堆,如果有他會返回此堆的引用地址,也就是a。
我們再來看第二個Main來繼續(xù)解釋:
如果沒有找到與所指向的堆的值相同的其他堆,他將返回b的引用地址;
***看第三個Main做***解釋:
如果傳遞進去的是字符串而不是引用地址,他一樣會檢索是否存在與此字符串相同的堆,如果有則返回此堆的引用地址,如無則駐留此字符串并返回其引用地址;
而這里所將的駐留也是String的特殊之處,字符串在被創(chuàng)建后不會被立即回收,即使已不存在對其引用;他會在被創(chuàng)建之后一直駐留在內(nèi)存中直至程序結束,大家可以查看MSDN解釋,下面將拿出一些MSDN的解釋來配合說明一下;
其中=>符號的是我做的注釋:
------MSDN解釋--Start------------------------------------------------------------------------------------
在1.1中
string str1 = String.Empty;
string str2 = String.Intern(String.Empty);
if ((object) str1) == ((object) str2);
...
==>是返回false,但在2.0中返回true,所以更加證實了如上所說;下面主要是講解了String的拘留池概念,大家理解上面概念后相信理解他也不成問題;
公共語言運行庫通過維護一個表來存放字符串,該表稱為拘留池,它包含程序中以編程方式聲明或創(chuàng)建的每個唯一的字符串的一個引用.因此,具有特定值的字符串的實例在系統(tǒng)中只有一個.例如,如果將同一字符串分配給幾個變量,運行庫就會從拘留池中檢索對該字符串的相同引用,并將它分配給各個變量.Intern 方法使用拘留池來搜索與 str 值相等的字符串.如果存在這樣的字符串,則返回拘留池中它的引用。
如果不存在,則向拘留池添加對 str 的引用,然后返回該引用.如果要減少應用程序分配的內(nèi)存總量,請記住留用字符串有兩個不希望出現(xiàn)的副作用:首先,為留用的 String 對象分配的內(nèi)存在公共語言運行庫 (CLR) 終止之前不大可能釋放.這是因為 CLR 對留用的 String 對象的引用可能保持到應用程序終止之后,甚至可能保持到應用程序域終止之后.其次,要留用字符串,必須先創(chuàng)建字符串.即使 String 對象使用的內(nèi)存最終將通過垃圾回收,仍然必須分配該內(nèi)存.
上面就說到了[為留用的 String 對象分配的內(nèi)存在公共語言運行庫 (CLR) 終止之前不大可能釋放.]
.NET Framework 2.0 版引入了 CompilationRelaxations.NoStringInterning 枚舉成員.
NoStringInterning 成員將程序集標記為不需要字符串拘留.可以使用 CompilationRelaxationsAttribute 屬性將NoStringInterning 應用于某個程序集.使用本機映像生成器 (Ngen.exe) 將該程序集安裝到本地計算機上的本機映像緩存時,不使用字符串拘留.這里所提到的本機映像可以改善內(nèi)存使用情況,大家可以查MSDN詳細了解;
【編輯推薦】