轉:String為值類型還是引用類型

来源:https://www.cnblogs.com/atomy/archive/2019/11/07/11810622.html

關於String為值類型還是引用類型的討論一直沒有平息,最近一直在研究性能方面的問題,今天再次將此問題進行一次明確。希望能給大家帶來點幫助,如果有錯誤請指出。 來看下麵例子: //值類型 int a = 1; int b = a; a = 2; Console.WriteLine("a is {0} ...


 關於String為值類型還是引用類型的討論一直沒有平息,最近一直在研究性能方面的問題,今天再次將此問題進行一次明確。希望能給大家帶來點幫助,如果有錯誤請指出。

 來看下麵例子:

 //值類型
 int a = 1;
 int b = a;
 a = 2;
 Console.WriteLine("a is {0},b is {1}", a, b);

 //字元串
 String str1 = "ab";
 String str2 = str1;
 str1 = "abc";
 Console.WriteLine("str1 is {0},str2 is {1}", str1, str2);
 Console.Read();

 根據上面的例子:你覺得輸出結果應該是什麼?

 輸出結果:
 //a is 2,b is 1
 //str1 is abc,str2 is ab
 str2依然是ab,並沒有隨str1的改變而改變。

 如果String是引用類型,按理Str1和Str指針都指向同一記憶體地址,如果Str的內容發生改變,Str1應該也會相應變化。

 此例子,看著String更像是值類型,但是MSDN卻說String是引用類型。

 引用類型包括:
 String
 所有數組(即使其元素是值類型)
 類類型(如Form)
 委托

 查看具體引用是否相同,如果Net能夠查看記憶體地址就容易了,但不允許,只能通過間接方法來實現,看下麵:

static void TestRefAddress()
{
    String str1 = "abc";
    String str2 = "abc";
    int a = 1;
    int b = 1;
    StringBuilder strb1 = new StringBuilder("abc");
    StringBuilder strb2 = new StringBuilder("abc");
    Console.WriteLine("Reference equal for string: " + Object.ReferenceEquals(str1, str2)); //結果true
    Console.WriteLine("Reference equal for int: " + Object.ReferenceEquals(a, b)); //結果false
    Console.WriteLine("Reference equal for StringBuilder: " + Object.ReferenceEquals(strb1, strb2)); //結果false
    Console.WriteLine("Value equal for string: " + str1.Equals(str2)); //結果true,類似於值類型
    Console.Read();
}

 結果為何出現如此情況,分析如下:

 Console.WriteLine("Reference equal for string: " + Object.ReferenceEquals(str1, str2)); //結果true,不同對象,但引用地址相同
 Console.WriteLine("Reference equal for int: " + Object.ReferenceEquals(a, b)); //結果false,值類型裝箱操作造成
 Console.WriteLine("Reference equal for StringBuilder: " + Object.ReferenceEquals(strb1, strb2)); //結果false,不同對象,引用地址不同
 Console.WriteLine("Value equal for string: " + str1.Equals(str2)); //結果true,類似於值類型

    由第一條結果,可以判定不同的String的,相同的值,其引用地址相同,再由第四條結果,str1.Equals(str2),兩者結合,可得出結論,兩個String,如果賦值為同一個值,在記憶體中只有一個字元串存在,兩個引用的地址相同。由此引出String的不變性。

    String的不變性:

    String最為顯著的一個特點就是它具有恆定不變性。我們一旦創建了一個String,在managed heap 上為他分配了一塊連續的記憶體空間,我們將不能以任何方式對這個String進行修改使之變長、變短、改變格式。所有對這個String進行各項操作(比如調用ToUpper獲得大寫格式的String)而返回的String,實際上另一個重新創建的String,其本身並不會產生任何變化。

    String 對象稱為不可變的(只讀),因為一旦創建了該對象,就不能修改該對象的值。有的時候看來似乎修改了,實際是String經過了特殊處理,每次改變值時都會建立一個新的String對象,變數會指向這個新的對象,而原來的還是指向原來的對象,所以不會改變。這也是String效率低下的原因。

    String的不變,並非說String不能改變,而是其值不能改變。

    在例子中str1="ab",這時在記憶體中就將“ab”存下來,如果再創建字元串對象,其值也等於“ab”,str2="ab",則並非再重新分配記憶體空間,而是將之前保存的“ab”的地址賦給str2的引用,這就能印證例子2中的結果。而當str1="abc"其值發生改變時,這時檢查記憶體,發現不存在此字元串,則重新分配記憶體空間,存儲“abc”,並將其地址賦給str1,而str2依然指向“ab”的地址,可以印證例子1中的結果。

    結論:
    String是引用類型,只是編譯器對其做了特殊處理。

    轉載來源:https://www.cnblogs.com/littlewrong/p/9927154.html


您的分享是我們最大的動力!

更多相關文章
  • System.IO.Pipelines是一個新的庫,旨在簡化在.NET中執行高性能IO的過程。它是一個依賴.NET Standard的庫,適用於所有.NET實現。 Pipelines誕生於.NET Core團隊,為使Kestrel成為業界最快的Web伺服器之一。最初從作為Kestrel內部的實現細節 ...
  • 前言 最近在做智能家居平臺,考慮到家居的控制需要快速的響應於是打算使用redis緩存。一方面減少資料庫壓力另一方面又能提高響應速度。項目中使用的技術棧基本上都是大家熟悉的springboot全家桶,在springboot2.x以後操作redis的客戶端推薦使用lettuce(生菜)取代jedis。 ...
  • 2019年11月8日,近期做項目開始實行前後端分離的方式開發,前端使用vue的框架,打包發佈後,調用後端介面出現跨域的問題,網上搜索出來的都是以下的配置方式: 但是,在我的項目中,按這種方式配置沒有效果,還會出現跨域的問題,後來發現是前後端請求設置的在Headers裡面傳輸token來進行校驗,那麼 ...
  • 網上看到很多人說 NPOI 的性能不行,自己寫了一個 NPOI 的擴展庫,於是想嘗試看看 NPOI 的性能究竟怎麼樣,道聽途說始終不如自己動手一試。 ...
  • 1. 沒有在Program里配置IIS webBuilder.UseIIS(); 2. StartupProduction 里AutoFac容器註入錯誤和新版的CORS中間件已經阻止使用允許任意Origin,即 AllowAnyOrgin設置了也不會生效 3. 可以嘗試下 在網站根目錄dotnet ...
一周排行
  • static void Main(string[] args) { string url = "https://go.microsoft.com/fwlink/?linkid=2108895&clcid=0x409"; DownloadBigFile(new Uri(url), "ssms.... ...
  • 1. 使用ASP.NET Core 3.x 構建 RESTful API - 1.準備工作 什麼是REST 什麼是REST REST一詞最早是在2000年,由Roy Fielding在他的博士論文《Architectural Styles and the Design of Network-base ...
  • wpf 兩個自定義控制項 一個是IP控制項,一個滑動條。先看下效果圖 IPControl 1、實際工作中有時需要設置IP信息,就想著做一個ip控制項。效果沒有window自帶的好,需要通過tab切換。但也能滿足使用。廢話不多說直接上代碼 IPControl.xaml IPControl.xaml.cs 2 ...
  • 近期和幾位做嵌入式開發的朋友閑聊過程中,一位朋友抱怨到:這C#太難用了,我想在N個窗體(或者是N個用戶組件之間)傳遞值都搞不定,非得要定義一個全局變數來存儲,然後用定時器來刷新值,太Low了。我急切的回答道:這很簡單,不就是委托的事嘛。那你來一個示例啊:朋友道。此為這篇博客的起因,所以此篇博客對於有 ...
  • 在面對對象編程中,類的三大特性分別為封裝,繼承,多態。其中多態的具體實現,依賴於三個方法,也就是虛方法,抽象類和介面。 多態的具體作用是什麼呢?或者說多態的存在有什麼意義呢?多態的存在有效的降低了程式的耦合度,在使用的時候,不僅可以表現大家都有的共性,還能在必要的時候突出一些特殊的的個性。 那麼如何 ...
  • [toc] 前言 在之前已經提到過,公用類庫Util已經開源,目的一是為了簡化開發的工作量,畢竟有些常規的功能類庫重覆率還是挺高的,二是為了一起探討學習軟體開發,用的人越多問題也就會越多,解決的問題越多功能也就越完善, 倉庫地址: "April.Util_github" , "April.Util_ ...
  • 【ASP.NET Core學習】在ASP.NET Core 種使用Entity Framework Core介紹,包括如何添加Entity Framwork Core,創建模型和遷移到資料庫,查詢數據,保存數據,使用事務,處理併發衝突 ...
  • 環境:MacOS 10.13 MAMAP Prophp 7.0.33 + xdebugVisual Studio Code前言我所理解的 POP Chain:利用魔術方法並巧妙構造特殊屬性調用一系列函數或類方法以執行某種敏感操作的調用堆棧反序列化常用魔法函數前言我所理解的 POP Chain:利用魔 ...
  • 當創建隊列jobs、監聽器或訂閱伺服器以推送到隊列中時,您可能會開始認為,一旦分派,隊列工作器決定如何處理您的邏輯就完全由您自己決定了。 嗯……並不是說你不能從作業內部與隊列工作器交互,但是通常情況下,哪怕你做了,也是沒必要的。 這個神奇的騷操作的出現是因為“InteractsWithQueue”這 ...
  • 在說正題之前先解釋一下交換機模式是個籠統的稱呼,它不是一個單獨的模式(包括了訂閱模式,路由模式和主題模式),交換機模式是一個比較常用的模式,主要是為了實現數據的同步。 首先,說一下訂閱模式,就和字面上的意思差不多主要就是一個生產者,多個消費者,同一個消息被多個消費者獲取,先看一下官網的圖示 整體執行 ...
x