為什麼引用型別string的行為卻是值型別

2021-06-04 11:58:00 字數 1548 閱讀 4042

首先,我們需要知道string的如下特性: 

1.字串做引數,傳遞的是引用,只是乙個指標的複製,你修改引數的指向,影響不到呼叫它的函式中的那個指標所指向的內容

2.字串不可修改。你以任何一種形式修改了字串(+,=等操作),源字串其實還在的,只是根據你的修改重新生成了乙個新的字串

3.如果需要修改,兩種方案,一是將修改後的字串返回;二是作引數傳字串時使用 ref 傳遞,這樣子函式中可以直接修改掉主函式中的指標指向,從而指向新的字串。

4  定義字串時,會先查clr內部的雜湊表。

字串型別就是乙個值型別的引用型別,用c++的概念來解釋的話,就是乙個指標,即*pstr.

*pstr = "123"; ----string中存放的是位址

但是c#中做了特殊的處理,就是第2條,不能對修改pstr所指向的位址的值。當你修改*pstr的值時,其實c#並沒有修改pstr所

指的記憶體的值,而是重新分配了一塊記憶體賦新的值,然後再將這塊新的記憶體的首位址賦值給指標pstr. 正是因為這條奇怪的規  則,使得c#中的引用型別的string的行為卻是值型別。

對於第1條,字串做引數時,其實就相當於c++中的指標做引數,*pstr,這樣傳遞的都是位址。但是因為第2條的原則規則,函式內用傳入的指標*pstr_input去修改值後,pstr_input指向了修改後的值的記憶體,而原始指標pstr還是指向原來的記憶體,pstr指向的記憶體的值和pstr_input指向的記憶體的值當然就不一樣了。

對於第3條, 當用 ref string 來傳遞引數時,其實就是相當於c++中的 **point指標的指標的方式了,這樣傳遞引數的時候,引數中就是原始引數*pstr指標pstr的指標,即傳遞的值就是&pstr. 這樣在函式中修改string時就會修改string的引用值,即修改*point的值。因為是用**point這樣的指標的指標的方式,函式中的對*point的修改時可以帶出去的。即函式中的修改,等於需改了主函式中的指標指向,函式中與主函式中都同時指向新的字串。

對於第4條,

string   str1="abc";

string   str2="abc";

當clr初始化時,會建立乙個內部的雜湊表,其中的鍵為字串,值為指向託管堆中字串的引用。剛開始,雜湊表為空,jit編譯器編譯方法時,會在雜湊表中查詢每乙個文字常量字串,首先會查詢"abc"字串,並且因為沒有找到,編譯器會在託管堆中構造乙個新的指向"abc"的string物件引用,然後將"abc"字串和指向該物件的引用新增到雜湊表中。

接著,在雜湊表中查詢第二個"abc",這一次由於找到了該字串,所以編譯器不會執行任何操作,**中再沒有其它的文字常量字串,編譯器的任務完成,**開始執行。執行時,clr發現第乙個語句需要乙個"abc"字串引用,於是,clr會在內部的雜湊表中查詢"abc",並且會找到,這樣指向先前建立的string物件的引用就被儲存在變數s1中,執行第二條語句時,clr會再一次在雜湊表中查詢"abc",並且仍然會找到,指向同乙個string物件的引用會被儲存在變數s2中,到此s1和s2指向了同乙個引用,所以system.object.equals(s1,s2)就會返回true了。

另外,c#中是不允許用new操作符建立string物件的,編譯器會報錯

為什麼string是引用型別

在c 中分為值型別和引用型別,值型別為int float bool char struct等簡單資料型別,引用型別有stirng,class。然而string的身為引用型別卻表現得與值型別十分相同。為什麼string為引用型別呢?首先明白string指向常量空間的位址。如果我們有乙個字串 strin...

C 反推為什麼string是引用型別

為什麼string是引用型別?c 裡面眾所周知,有兩大型別,分別引用型別和值型別。引用型別有類 class 和字串 string 而值型別有int double char bool等等。分析string為什麼是引用型別之前,要分析一下,int整型和bool布林值為什麼是值型別。int和bool這倆型...

筆記 引用型別 String型別

string 型別是字串包裝型別 var str new string hello world 這是乙個特殊的物件型別與引用型別不同的是它的生命週期,它的生命週期在 執行完瞬間就會被銷毀 sring型別的例項都有乙個length 屬性 可以str.length 訪問 1.字元方法 charat ch...