裝箱和拆箱-值類型和引用類型的區別

来源:https://www.cnblogs.com/lvqiang/archive/2019/09/24/11577486.html
-Advertisement-
Play Games

一、概述 在C#中,數據根據變數的類型以兩種方式中的一種存儲在一個變數中。變數的類型分為兩種:引用類型和值類型,這也是CLR支持的兩種類型。 二、定義 1.引用類型: 分配在堆上的類型稱為引用類型。 解析:一個可以稱為”類“的類型都是引用類型。 引用類型總是從托管堆上分配的,常用的語法就是New X ...


一、概述

在C#中,數據根據變數的類型以兩種方式中的一種存儲在一個變數中。變數的類型分為兩種:引用類型和值類型,這也是CLR支持的兩種類型。

 

二、定義

1.引用類型:

分配在堆上的類型稱為引用類型。

解析:一個可以稱為”類“的類型都是引用類型。 引用類型總是從托管堆上分配的,常用的語法就是New XX(). C#的new 操作符會返回對象的指針 - 也就是指向對象數據的記憶體地址的一個引用。引用類型的傳遞其實傳遞的是對象的指針(string類型比較特殊),所以在特定的場景下性能是高於值類型的。一個引用類型在創建時預設為null,也就是說當前變數不指向一個有效的對象,也就是我們常遇到的異常“未將對象引用設置到對象的實例”。

2.值類型:

值類型一般線上程棧上分配。

 

三、區別

我們總圖然後詳細分析。

 

1.值類型的數據存儲在記憶體的棧中,記憶體分配是自動釋放,在GC的控制之外,不會對GC造成壓力,所以值類型存取速度快;引用類型的數據存儲在記憶體的堆中,在.NET中會有GC來釋放,而記憶體單元中只存放堆中對象的地址,在.NET中會有GC來釋放所以存取速度慢。我們可以這麼理解,值類型就是現金,要用直接用;引用類型是存摺,要用還得先去銀行取現。

 當然,值類型雖然存取速度快,但也不能卵用,舉個例子:我自定義一個struct 類型作為一個方法的參數會發生什麼呢?每次調用都會發生全欄位的賦值,這是不可接受的,這也是典型的值類型勿用場景。

2.值類型表示實際數據,引用類型表示指向存儲在記憶體堆中的數據的指針或引用。

3.值類型繼承自System.ValueType,引用類型繼承自System.Object。

4.值類型總是包含一個值,而引用類型可以是null。

 

四、封箱和拆箱

封箱(boxing)是把值類型轉換為引用類型(System.Object)。拆箱(unboxing)是相反的轉換過程。

封箱的過程:

1.在托管堆中分配好記憶體,分配的記憶體量是值類型的各個欄位需要的記憶體量加上托管堆上所以對象的兩個額外成員(類型對象指針,同步塊索引)需要的記憶體量。

2.值類型的欄位複製到新分配的堆記憶體中。

3.返回對象的地址,這個地址就是這個對象的引用。

 

 從圖可知,對象 o 存的是地址引用,指向的是堆上的值,這個值的類型和變數 i 一樣,也是 int 類型,值(123)也就是從棧上變數 i複製過來的一個副本值而已。(所以裝箱就是在堆上分配好記憶體,再複製棧上的值,再將堆的地址引用返回到棧上)

拆箱的過程:

1.獲取已經裝箱的值類型實例的指針。

2.把獲取到的值複製到棧。

所以裝箱是比較耗費性能的,還有可能引發一次GC操作,而拆箱只是一個獲取指針的過程耗費資源要比裝箱小的多。註意:一個對象拆箱之後只能還原為原先未裝箱之前的類型,例如:你不能把int32類型裝箱後還原為int16類型。

引用類型和值類型區別實例:

1.我們首先定義一個類,用來處理數據。

 

 

 2.在控制器中先定義兩個數據類型,賦值都為0。調用上面的類,看看會輸出什麼。

 

 

 前臺頁面(簡單實例,就直接用session了,平時可不要這麼寫)

 

 

 輸出頁面:

 

 

 這究竟是怎麼回事呢,引用類型的值為什麼會改變呢?下麵我們詳細分析下:

 

首先,我們先要理解ref是什麼,對於Class類型使用 ref,是為了保持引用的地址是一致的。所以在使用引用參數時,必須在方法的聲明和調用中都使用ref修飾符。

如果還不清楚,就跟著代碼走一遍吧!

1.在控制器中先打一個斷點,我們可以在局部變數中看到他們的初始值都為0.

 

 

 

2.轉到方法Test2中,在還沒有開始修改引用類型的值的時候,a的值還是0.

 

 

 3.在走過方法Test2後,我們看到引用類型a的值變為了5454.

 

 

 4.同樣操作,我們在Test方法後得到的值類型數據還是0。

 

 

 同樣是修改變數的值,為什麼值類型的卻並沒有改變呢?這就是他們各自的特性造成的了。傳遞引用參數的時候傳遞的是一個地址的值,在Test2方法內,形參a的地址被實參str給修改了,所以返回時,a的地址變了,由原先的指向0的地址變為了指向5454的地址,所以輸出了5454.而傳遞值類型參數的時候傳遞的是一個真實的值,他沒有地址,在Test方法內,形參b的值把這個值“0”拷貝一份,然後把拷貝後的值傳遞到了方法內部,所以,在方法內改變的只是拷貝的值,方法結束後b的值還是0.

 

在下麵的視窗可以更加直觀的看出,變數a的地址在變化。

 


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

-Advertisement-
Play Games
更多相關文章
  • ASP.NET有個大佬,HttpContext(在.Net Core中依然是它)Http請求的上下文,任何一個環節都是需要HttpContext的,需要的參數信息,處理的中間結果,最終的結果,都是放在HttpContext,是一個貫穿全局的對象。 所謂的六大對象,其實就是HttpContext的屬性 ...
  • public class CEBSignClient { public void StartSignClient() { } private static SignClientConfig _signClientConfig; public static SignClientConfig CebSi ...
  • 瀏覽器到網站程式 上一篇中,介紹IHttpModule的時候,自定義一個類CustomHttpModule繼承自IHttpModule,自定義一個事件,並配合配置文件,就可以執行自定義Module中的Init方法。我們在瀏覽一個View視圖,並新建一個WebForm頁面,也瀏覽一下 我們可以看出來, ...
  • https://www.cnblogs.com/JimmyZhang/archive/2007/09/04/880967.html IHttpModule HTTPRuntime(運行時)。在一個控制台程式中,程式的入口是Program中的Main方法。那麼,一個網站的入口在哪裡呢?在最開始的ash ...
  • 兩數之和 給定一個整數數組 nums 和一個目標值 target,請你在該數組中找出和為目標值的那 兩個 整數,並返回他們的數組下標。 你可以假設每種輸入只會對應一個答案。但是,你不能重覆利用這個數組中同樣的元素。 示例: 給定 nums = [2, 7, 11, 15], target = 9 因 ...
  • 一. 介紹 在一上篇中介紹了Exceptionless的基本使用,這篇主要講Exceptionless結合Nlog的實現雙重日誌記錄,包括Exceptionles的UI可視化日誌以及Nlog的txt文件日誌。再是從Apollo配置中心讀取配置文件,當系統越龐大越多時,需要配置的參數也越來越多,可以通 ...
  • 本文基於 2019/9/24 剛剛發佈的 ASP.NET Core 3.0 正式版,全文翻譯自微軟官方文檔英文版 "What's new in ASP.NET Core 3.0" 。 重點介紹了 ASP.NET Core 3.0 中最重要的更改,並提供相關文檔的連接。 由於官方文檔目前只有英文版... ...
  • 資料庫中部分表欄位允許空值,則代碼中實體類對應的欄位類型為可空類型Nullable,如int?,DateTime?,null值欄位序列化返回的值都為null,前端對應欄位賦值需要做null值判斷,隨想到全局把null替換為"" 網上找的方案都是重寫了DefaultContractResolver,但... ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...