1、概述html
String是咱們日常用得最多的基元類型之一,雖然咱們常用並且感到很是熟悉;但不少朋友只知道一個字符串的定義、使用或知道如何使用StringBuilder來達到高效構建字符串,可是有多少朋友有興趣去了解背後的一些「不爲咱們知道的祕密」?算法
2、爲何把String加入到基元類型中函數
在之前的面向過程語言中,並無String這個類型,定義一個字符串的方式則採用一個Char[],雖然提供了對字符串的操做、比較等函數,可是仍是不夠方便也不太符合面向對象作法,因此在面嚮對象語言中,string也加入了基元類型的隊列中;佈局
3、String核心特徵immutable(不可變)性能
表明一個不可變的順序字符集,也就是說一經建立,字符串編不能以任何方式進行修改;具備如下3個優勢:ui
1. 容許在一個字符串上執行各類操做,而不實際地更改字符串;spa
2. 在操做或訪問一個字符串的時候不會發生線程同步的問題;線程
3. 基於性能的考慮,String類型與CLR緊密集成,CLR知道String類型中定義的字段如何佈局,並且CLR會直接訪問,因此開發的時只好將String定義爲密封類(Sealed);指針
4、被重寫的兩個方法GetHashCode與Equalscode
1. GetHashCode方法進行了重寫,目的是爲了知足兩個字符串的判斷;
2. Equals方法進行重寫,其中Equals方法最終仍是調用了GetHashCode方法來進行判斷;
5、「==」、Equals、Compare,字符串判斷到底用哪一個好點?
1. String對「==」操做符進行重載,內部實現進行了空值判斷後,再調用Equals進行判斷(因此採用"=="操做符,不會拋出空指針異常)
2. String的Equals方法,由於調用Equals方法的時候,直接經過返回HashCode進行比較,效率最高,有可能對象爲空,有可能會拋空指針異常,因此用的時候須要留意;
3. String的Compare方法:該方法是一個靜態方法,內部實現是首先判斷字符串的長度是否相等,若是長度不相等,直接返回結果,若是長度相等,則會採用逐個字符進行判斷,若是方法中的CultureInfo不爲空,則判斷的過程當中會逐個字符進行展開(這裏涉及到語言的問題,若是採用德語會把"β"展開爲"ss",因此」strasse」跟」staβe」的判斷結果是相同的);
注:若是通常狀況下,建議採用Equals進行判斷,效率最高,但若是沒法確保方法Equals的調用者是否不爲null,建議仍是採用==或者 "XXXX".Equals(obj),若是須要用到多語言(國際化)判斷的時候,能夠考慮用Compare;
6、拘留池(Interning)
字符串操做(好比Compare)的作法是不少程序常見的操做,這樣的操做可能形成內存中複製同一個字符串的多個實例(算法內部操做致使),爲了達到節省內存的效果,CLR採用了一種叫「字符串留用的技術」(String Interning),開闢了一塊名爲「拘留池」的空間專門用於存放字符串,而拘留池在程序初始化的時候,會把元數據默認加載到「拘留池」中,並且不會受到垃圾回收器的影響,只有在程序被關閉的時候纔會釋放「拘留池」中的資源;
7、存儲方式,大體分爲如下3種:
1. 以常量的方式來定義很保存字符串,好比:var value = "abc";
2. 以對象的方式來保存到堆中:好比 var value = new string('a');
3. 以對象的方式構造而後存放到拘留池(其實常量的方式定義後,默認也會把字符串加入到駐留池中);
能夠參考如下代碼和內存分配圖進行理解:
注:默認是不從拘留池中加載,而是直接採用ldstr的特殊指令得到字符串」abc」,但能夠確認的是」元數據」跟「拘留池」中的字符串是用個對象;
8、案例分析
var A = "ab" + "c";
var B = "abc";
2. 如下代碼的HashCode是否相同,他們是不是同個對象:
var A = Console.ReadLine(); //輸入"abc"
var B = Console.ReadLine(); //輸入"abc"
3. 如下代碼的HashCode是否相同,他們是不是同個對象:
var A = Console.ReadLine(); //輸入"abc"
var B = Console.ReadLine(); //輸入"abc"
var A = string.Intern(B);
結果請查看這裏