網站首頁 編程語言 正文
一、值類型和引用類型的區別
.NET的類型可以分為兩類:值類型和引用類型。這兩種類型各有特點,即使它們都繼承自System.Object,并且有裝箱和拆箱等操作確保兩種類型可以方便地交互,但是理解值類型和引用類型將有助于程序員編寫出高效的代碼,相反的,在不理解值類型和引用類型的情況下,程序員很容易編寫出可以正確執行但性能較差的代碼。
所有.NET的類型都可以分為兩類:值類型和引用類型。最簡單也最明確的一個區分標準是:所有的值類型都繼承自System.ValueType(System.ValueType繼承自System.Object),也就是說,所有繼承自System.ValueType的類型都是值類型,而其他類型都是引用類型。常用的值類型包括結構、枚舉、整數型、浮點型、布爾型等,而在C#中所有以class關鍵字定義的類型都是引用類型。
1、賦值時的區別
引用類型和值類型最顯著的一個區別在于變量的賦值問題。值類型的變量將直接獲得一個真實的數據副本,而對引用類型的賦值僅僅是把對象的引用賦給變量,這樣就可能導致多個變量引用到一個實際對象實例上。
來看下面一個簡單的示例:首先為了測試建立一個簡單的引用類型和一個簡單的值類型。然后在Main方法中,測試對值類型和引用類型對象進行賦值的不同結果,代碼如下:
using System; namespace ConsoleApp1 { ////// 一個簡單的引用類型 /// public class Ref { public int iValue { get; set; } public Ref(int i) { iValue = i; } public override string ToString() { return $"iValue的值為:{iValue.ToString()}"; } } ////// 一個簡單的值類型 /// public struct Val { public int Value { get; set; } public Val(int i) { Value = i; } public override string ToString() { return $"Value的值為:{Value.ToString()}"; } } class Program { static void Main(string[] args) { // 測試引用類型的賦值 Ref ref1 = new Ref(1); Ref ref2 = ref1; // 賦值 ref2.iValue = 2; // 測試值類型的賦值 Val val1 = new Val(1); Val val2 = val1; val2.Value = 2; //輸出 Console.WriteLine($"ref1:{ref1}"); Console.WriteLine($"ref2:{ref2}"); Console.WriteLine($"val1:{val1}"); Console.WriteLine($"val2:{val2}"); Console.ReadKey(); } } }
簡單分析上面的代碼,程序定義了一個引用類型Ref和一個值類型Val,兩者的內容幾乎完全相同。在Main方法中,分別測試了引用類型和值類型的賦值。當代碼把一個引用類型變量賦值給另一個引用變量:Ref ref2 = ref1時,實際上是把ref1的對象引用賦給了ref2,這樣,兩個引用變量實際指向了同一個對象。如圖所示:
而值類型的賦值則不同,val1和val2都保留了屬于自己的數據副本,所以當val2改變時,val1不受到影響。如圖所示:
上面代碼的輸出結果:
2、內存分配的區別
除了賦值的區別,引用類型和值類型在內存的分配位置上也有區別。引用類型的對象將會在堆上分配內存,而值類型的對象則會在堆棧上分配內存。堆棧的空間相對有限,但運行效率卻比高的多。
3、來自繼承結構的區別
最后,由于所有的值類型都有一個共同的基類:System.ValueType,所以值類型擁有一些引用類型不具有的共同性質,較重要的一點是值類型的比較方法:Equals方法的實現有了改變。所有的值類型都實現了內容的比較,而引用類型在沒有重寫Equals方法的情況下,仍然采用引用比較。還是以上面的代碼為了,看下面的代碼:
using System; namespace ConsoleApp1 { ////// 一個簡單的引用類型 /// public class Ref { public int iValue { get; set; } public Ref(int i) { iValue = i; } public override string ToString() { return $"iValue的值為:{iValue.ToString()}"; } } ////// 一個簡單的值類型 /// public struct Val { public int Value { get; set; } public Val(int i) { Value = i; } public override string ToString() { return $"Value的值為:{Value.ToString()}"; } } class Program { static void Main(string[] args) { //// 測試引用類型的賦值 //Ref ref1 = new Ref(1); //Ref ref2 = ref1; //// 賦值 //ref2.iValue = 2; //// 測試值類型的賦值 //Val val1 = new Val(1); //Val val2 = val1; //val2.Value = 2; //輸出 //Console.WriteLine($"ref1:{ref1}"); //Console.WriteLine($"ref2:{ref2}"); //Console.WriteLine($"val1:{val1}"); //Console.WriteLine($"val2:{val2}"); // 測試引用類型的賦值 Ref ref1 = new Ref(1); Ref ref2 = new Ref(1); // 測試值類型的賦值 Val val1 = new Val(1); Val val2 = new Val(1); Console.WriteLine(ref1.Equals(ref2)); Console.WriteLine(val1.Equals(val2)); Console.ReadKey(); } } }
程序輸出結果:
在Main方法中,分別定義了一對內容完全相同的值類型對象和引用類型對象,調用Equals方法來比較,發現值類型對象比較返回true,而引用類型對象比較返回false。
二、總結
所有繼承自System.ValueType的類型都是值類型,而其他類型都是引用類型。值類型的賦值會產生一個新的數據副本,所以每個值類型都擁有一個數據副本。而引用類型的賦值則是賦值引用。值類型的對象分配在堆棧上,而引用類型的對象分配在堆上。當比較兩個值類型時,進行的是內容比較。而比較兩個引用類型時,進行的是引用比較。
上面列舉的僅僅是值類型和引用類型的一些主要區別,通過這些本質區別,可以產生更多的細節區別,有興趣的話可以自行研究。
原文鏈接:https://www.cnblogs.com/dotnet261010/p/12324317.html
相關推薦
- 2022-11-01 如何使用Kubernetes自定義資源(CRD)詳解_云其它
- 2024-03-14 docker導出導入鏡像或容器
- 2024-02-01 QueryWrapper、LambdaQueryWrapper、QueryChainWrapper、
- 2022-06-29 Python?高級教程之線程進程和協程的代碼解析_python
- 2023-03-02 SQLServer?清理日志的實現_MsSql
- 2023-03-18 pandas檢查和填充缺失值的N種方法總結_python
- 2022-10-31 Python3邏輯運算符與成員運算符_python
- 2023-05-23 pytorch中backward()方法如何自動求梯度_python
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支