String - 興趣解讀

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、被重寫的兩個方法GetHashCodeEqualscode

1.     GetHashCode方法進行了重寫,目的是爲了知足兩個字符串的判斷;

2.     Equals方法進行重寫,其中Equals方法最終仍是調用了GetHashCode方法來進行判斷;

5、「==」、EqualsCompare,字符串判斷到底用哪一個好點?

1.     String對「==」操做符進行重載,內部實現進行了空值判斷後,再調用Equals進行判斷(因此採用"=="操做符,不會拋出空指針異常)

2.     StringEquals方法,由於調用Equals方法的時候,直接經過返回HashCode進行比較,效率最高,有可能對象爲空,有可能會拋空指針異常,因此用的時候須要留意;

3.     StringCompare方法:該方法是一個靜態方法,內部實現是首先判斷字符串的長度是否相等,若是長度不相等,直接返回結果,若是長度相等,則會採用逐個字符進行判斷,若是方法中的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.     以對象的方式構造而後存放到拘留池(其實常量的方式定義後,默認也會把字符串加入到駐留池中); 

能夠參考如下代碼和內存分配圖進行理解:

    // 驗證字符串常量默認加載到元數據,默認會把元數據中的字符串加載到拘留池
var  data =  " abc " ;        // 此聲明方式,會把該變量定義爲字符串常量,而後存入元數據中
    var a =  " a ";             // 同上
     var b =  " b ";             // 同上
     var c =  " c ";             // 同上
     var ab = a + b;          // 根據線程棧上的a、b地址獲取到堆上的a、b實例,而後把兩個實例的結果進行運算後產生一個新對象,最後新對象地址賦給ab變量
     var abc = a + b + c;     // 同上
     var abResult =  string.IsInterned(ab);         // 返回結果爲null,也就是說沒有把字符串"ab"存入拘留池中;
     var abcResult =  string.IsInterned(abc);      // 返回結果爲"abc",也就是說已經把字符串(這裏是常量)"abc"存放到拘留池中;
     var empty =  string.Empty;         // 初始化的時候,從String類型對象中獲取靜態屬性Empty的數據;
     var strEmpty =  "";                // 產生一個值爲空的String對象;

     var a1 =  " abc ";
     var a2 =  string.IsInterned(a1);
     var result =  object.ReferenceEquals(a1, a2);    

            

     注:默認是不從拘留池中加載,而是直接採用ldstr的特殊指令得到字符串」abc」,但能夠確認的是」元數據」跟「拘留池」中的字符串是用個對象; 

8、案例分析

   1 . 如下代碼的HashCode是否相同,它們是不是同個對象;

      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);

 結果請查看這裏

相關文章
相關標籤/搜索