靜態(tài)網(wǎng)站制作價(jià)格seo是什么公司
文章目錄
- 知識(shí)回顧
- 一、棧(Stack)和堆(Heap)
- 1、什么是棧和堆
- 2、為什么要分棧和堆
- 3、棧和堆的區(qū)別
- 棧
- 堆
- 4、總結(jié)
- 二、值類(lèi)型和引用類(lèi)型
- 1、那么值類(lèi)型和引用類(lèi)型到底有什么區(qū)別呢?
- 值類(lèi)型
- 引用類(lèi)型
- 2、總結(jié)
- 三、特殊的引用類(lèi)型string
- 1、為什么說(shuō)string是特殊的引用類(lèi)型?
- 2、理解字符串(string)引用類(lèi)型
- 3、如何證明呢?
- 使用 `GetHashCode` 方法
- 通過(guò)斷點(diǎn)調(diào)試直接查看變量指針內(nèi)存地址
- 4、總結(jié)
- 專(zhuān)欄推薦
- 完結(jié)
知識(shí)回顧
C# 中的變量類(lèi)型可以分為 值類(lèi)型
和 引用類(lèi)型
兩大類(lèi)。
值類(lèi)型
變量類(lèi)型 | 描述 | 范圍 |
---|---|---|
byte | 無(wú)符號(hào)8位整數(shù) | 0 到 255 |
sbyte | 有符號(hào)8位整數(shù) | -128 到 127 |
short | 有符號(hào)16位整數(shù) | -32,768 到 32,767 |
ushort | 無(wú)符號(hào)16位整數(shù) | 0 到 65,535 |
int | 有符號(hào)32位整數(shù) | -2,147,483,648 到 2,147,483,647 |
uint | 無(wú)符號(hào)32位整數(shù) | 0 到 4,294,967,295 |
long | 有符號(hào)64位整數(shù) | -9,223,372,036,854,775,808 到 9,223,372,036,854,775,807 |
ulong | 無(wú)符號(hào)64位整數(shù) | 0 到 18,446,744,073,709,551,615 |
float | 32 位單精度浮點(diǎn)數(shù) | ±1.5 × 10^?45 到 ±3.4 × 10^38(精度約7位有效數(shù)字) |
double | 64 位雙精度浮點(diǎn)數(shù) | ±5.0 × 10^?324 到 ±1.7 × 10^308(精度約15–16位有效數(shù)字) |
decimal | 128 位高精度小數(shù) | ±1.0 × 10^?28 到 ±7.9 × 10^28(精度約28–29位有效數(shù)字) |
bool | 8 位布爾型 | true 或 false |
char | 16 位單一字符型 | Unicode字符(0 到 65,535) |
引用類(lèi)型
變量類(lèi)型 | 描述 | 范圍 |
---|---|---|
string | 字符串 | 任意長(zhǎng)度的字符序列(理論上最多可達(dá)到 2GB) |
一、棧(Stack)和堆(Heap)
要了解值類(lèi)型和引用類(lèi)型的區(qū)別,我們得先得棧和堆的概率有個(gè)了解。
1、什么是棧和堆
簡(jiǎn)單理解就是,程序運(yùn)行時(shí),它的數(shù)據(jù)必須存儲(chǔ)在內(nèi)存中。棧和堆就是計(jì)算機(jī)內(nèi)存中的兩種不同的存儲(chǔ)區(qū)域。
2、為什么要分棧和堆
通過(guò)分棧和堆,程序可以在性能和內(nèi)存管理上做出平衡,從而讓程序既高效又靈活。
3、棧和堆的區(qū)別
棧
- ??臻g比較小,但是讀取速度快。
- 棧存儲(chǔ)的是一些簡(jiǎn)單的數(shù)據(jù)
- 棧遵循
先進(jìn)后出
原則,棧就像一個(gè)堆疊的盤(pán)子。你每次放入一個(gè)新盤(pán)子(數(shù)據(jù)),都會(huì)把它放在最上面。拿東西的時(shí)候,也都是從最上面拿,所以非??焖佟?/li> - 棧里的數(shù)據(jù)只在當(dāng)前函數(shù)或方法運(yùn)行時(shí)有效,一旦方法執(zhí)行完畢,這些數(shù)據(jù)就會(huì)自動(dòng)被銷(xiāo)毀。
堆
- 堆空間比較大,但是讀取速度慢。
- 堆存儲(chǔ)的是一些較大的數(shù)據(jù)。
- 堆就像一個(gè)大大的垃圾堆,可以隨意放東西。它不按照順序來(lái)存放數(shù)據(jù),而是根據(jù)需要分配空間,可以存儲(chǔ)更復(fù)雜的對(duì)象
- 堆中的數(shù)據(jù)不會(huì)像棧那樣自動(dòng)清理。(但在 C# 中,
垃圾回收
會(huì)自動(dòng)清理不再使用的對(duì)象)
4、總結(jié)
實(shí)際上,我們寫(xiě)程序并不需要關(guān)心內(nèi)存是如何使用的,C#已經(jīng)幫我們做好了。這里只是簡(jiǎn)單介紹這個(gè)概念,有些知識(shí)看不懂也沒(méi)關(guān)系,比如垃圾回收
,后面肯定還會(huì)詳細(xì)介紹。現(xiàn)在有個(gè)印象就行。
二、值類(lèi)型和引用類(lèi)型
在 C# 中,數(shù)據(jù)類(lèi)型分為兩大類(lèi):值類(lèi)型(Value Types)和 引用類(lèi)型(Reference Types)。
我們目前學(xué)了值類(lèi)型和引用類(lèi)型只有變量,但是其實(shí)不止
- 值類(lèi)型其實(shí)還有
結(jié)構(gòu)體(Struct)
、枚舉(Enum)
, - 引用類(lèi)型還有
類(lèi)(Class)
、數(shù)組(Array)
、委托(Delegate)
。
這些我們后面會(huì)一一介紹,現(xiàn)在了解一下就行。
1、那么值類(lèi)型和引用類(lèi)型到底有什么區(qū)別呢?
因?yàn)橹粚W(xué)了變量,這里就用變量舉例。
值類(lèi)型
- 直接存儲(chǔ)數(shù)據(jù),值類(lèi)型的變量直接保存它們的數(shù)據(jù)。值類(lèi)型直接存儲(chǔ)在
棧
上。 - 值類(lèi)型賦值時(shí),會(huì)
復(fù)制值本身
。
比如
int a, b;
a = 100;
b = a;
Console.WriteLine("a的值:" + a);
Console.WriteLine("b的值:" + b);a = 20; // 重新給a賦值,b的值不會(huì)改變
Console.WriteLine("a的值:" + a);
Console.WriteLine("b的值:" + b);
打印結(jié)果,正如前面所說(shuō),重新給a賦值,b的值不會(huì)改變
畫(huà)圖說(shuō)明
解釋
:
-
聲明變量 int a, b;
當(dāng)你聲明兩個(gè)整數(shù)變量 a 和 b 時(shí),編譯器會(huì)在棧上為它們各自分配32位的存儲(chǔ)空間。此時(shí),這兩個(gè)存儲(chǔ)空間是空的,沒(méi)有初始化任何值。 -
賦值 a = 100;
當(dāng)你給變量 a 賦值為 20 時(shí),棧上的存儲(chǔ)空間 a 會(huì)被寫(xiě)入值 20。這個(gè)操作不會(huì)重新分配內(nèi)存,而是直接在已經(jīng)分配的內(nèi)存位置寫(xiě)入新的值。 -
賦值 b = a;
當(dāng)你執(zhí)行 b = a; 時(shí),棧上的存儲(chǔ)空間 b 會(huì)被寫(xiě)入 a 的當(dāng)前值。此時(shí),a 和 b 都存儲(chǔ)了值 20,但它們是獨(dú)立的存儲(chǔ)空間。 -
重新賦值 a = 20;
當(dāng)你再次給 a 賦值為 20 時(shí),棧上的存儲(chǔ)空間 a 會(huì)被更新為新的值 20。這不會(huì)重新分配內(nèi)存,而是直接在已經(jīng)分配的內(nèi)存位置寫(xiě)入新的值。
引用類(lèi)型
- 間接存儲(chǔ)數(shù)據(jù),引用類(lèi)型的變量保存的是對(duì)實(shí)際數(shù)據(jù)所在位置的
引用或地址
(也叫指針),而不是數(shù)據(jù)本身。引用類(lèi)型存儲(chǔ)在棧上的引用
(或指針)和堆上的實(shí)際數(shù)據(jù)
。 - 引用類(lèi)型賦值時(shí),會(huì)
復(fù)制引用
,但實(shí)際的數(shù)據(jù)不會(huì)復(fù)制。
畫(huà)圖說(shuō)明,假設(shè)a b c都是引用類(lèi)型
解釋
:
-
聲明引用類(lèi)型 a 和 b;
這時(shí) a 和 b 都是空引用,它們?cè)跅I戏峙淞丝臻g,但它們指向的堆內(nèi)存地址尚未確定,二者目前都沒(méi)有引用任何實(shí)際的對(duì)象。
-
給 a 賦值:
此時(shí),a 作為棧上的一個(gè)引用變量,指向堆上的值。b 仍然是空引用。
-
b = a; b 也指向 a 的堆值:
此時(shí),a 和 b 都存儲(chǔ)相同的堆內(nèi)存地址,指向相同的堆對(duì)象。
-
a 修改為新值:
這時(shí)候a b的值就都變成了新值
-
重新定義 c,并給 c 賦值
此時(shí),c 是一個(gè)新的引用類(lèi)型變量,它在棧上存儲(chǔ)了指向堆上c值的地址,且與 a 和 b 的值互不影響。
ps
:有些小伙伴可能會(huì)說(shuō)了,前面不是說(shuō)了string不就是引用類(lèi)型嗎,為什么不用string舉例呢,這樣不是更加直觀(guān)?其實(shí)是因?yàn)閟tring是特殊的引用類(lèi)型,這個(gè)問(wèn)題我接下來(lái)會(huì)說(shuō)。
2、總結(jié)
特性 | 值類(lèi)型 (Value Type) | 引用類(lèi)型 (Reference Type) |
---|---|---|
存儲(chǔ)方式 | 存儲(chǔ)數(shù)據(jù)的值本身 | 存儲(chǔ)數(shù)據(jù)的引用(內(nèi)存地址) |
賦值行為 | 賦值時(shí)會(huì)復(fù)制數(shù)據(jù),原始值和復(fù)制值互不影響 | 賦值時(shí)會(huì)復(fù)制引用,兩個(gè)變量指向同一個(gè)對(duì)象 |
存儲(chǔ)位置 | 通常存儲(chǔ)在棧上 (stack),但結(jié)構(gòu)體和其他類(lèi)型可能存儲(chǔ)在堆上 | 存儲(chǔ)在堆上 (heap),引用存儲(chǔ)在棧上 |
初始化 | 默認(rèn)值為零或空值(如 0 、false 、null ) | 默認(rèn)值為 null |
內(nèi)存管理 | 系統(tǒng)負(fù)責(zé)管理內(nèi)存(棧上分配的內(nèi)存自動(dòng)釋放) | 由垃圾回收器 (GC) 管理內(nèi)存 |
常見(jiàn)類(lèi)型 | 基本數(shù)據(jù)類(lèi)型(如 int 、float 等)、結(jié)構(gòu)體、枚舉 | 類(lèi)、數(shù)組、委托、字符串等 |
三、特殊的引用類(lèi)型string
1、為什么說(shuō)string是特殊的引用類(lèi)型?
學(xué)了前面引用類(lèi)型的知識(shí),我們可以拿string測(cè)試一下試試。
string str1, str2;
str1 = "名";
str2 = str1;
Console.WriteLine("str1的值:" + str1);
Console.WriteLine("str2的值:" + str2);str1 = "字";//重新賦值str1
Console.WriteLine("str1的值:" + str1);
Console.WriteLine("str2的值:" + str2);
按前面引用類(lèi)型的概念,可能你想說(shuō)第二次打印的結(jié)果應(yīng)該是"字" "字"
。
實(shí)際上真是這樣嗎?我先來(lái)看看執(zhí)行結(jié)果
有人會(huì)說(shuō),如果是值類(lèi)型,結(jié)果倒還說(shuō)的過(guò)去.但是不是說(shuō)string是引用類(lèi)型么?如果是引用類(lèi)型的話(huà)。輸出的結(jié)果難道不應(yīng)該是: "名""名""字" "字"
么?
2、理解字符串(string)引用類(lèi)型
理解字符串(string)在C#中的行為確實(shí)可能有些困惑,因?yàn)樗鼈冊(cè)谀撤N程度上表現(xiàn)出值類(lèi)型和引用類(lèi)型的特性。讓我們來(lái)詳細(xì)解釋一下。
-
字符串是
不可變
的
字符串在C#中是不可變的,這意味著一旦你創(chuàng)建了一個(gè)字符串對(duì)象,就不能修改它的內(nèi)容。當(dāng)你嘗試修改一個(gè)字符串時(shí),實(shí)際上是創(chuàng)建了一個(gè)新的字符串對(duì)象。 -
字符串為什么是
引用類(lèi)型
因?yàn)樗鼈冊(cè)诙焉戏峙鋬?nèi)存,并且在棧上存儲(chǔ)對(duì)堆上對(duì)象的引用。因此,多個(gè)變量可以引用同一個(gè)字符串對(duì)象。
3、如何證明呢?
使用 GetHashCode
方法
雖然這并不返回內(nèi)存地址,但 GetHashCode 方法會(huì)返回一個(gè)與字符串內(nèi)容相關(guān)的哈希值。這個(gè)值可以作為字符串的“標(biāo)識(shí)符”,有時(shí)候在調(diào)試中,它能幫助你判斷是否為同一個(gè)字符串實(shí)例。
string str1 = "xxxx";
string str2 = str1;
Console.WriteLine(str1.GetHashCode());
Console.WriteLine(str2.GetHashCode());str1 = "yyyy";
Console.WriteLine(str1.GetHashCode());
Console.WriteLine(str2.GetHashCode());
結(jié)果
通過(guò)斷點(diǎn)調(diào)試直接查看變量指針內(nèi)存地址
值類(lèi)型,一開(kāi)始內(nèi)存地址就不一樣
string引用類(lèi)型,開(kāi)始地址一樣,重新賦值后地址不一樣了
4、總結(jié)
字符串不叫值類(lèi)型,因?yàn)樗鼈兇_實(shí)具有引用類(lèi)型的基本特性:在堆上分配內(nèi)存,并且在棧上存儲(chǔ)引用。盡管字符串的不可變性使得它們?cè)谀承┓矫姹憩F(xiàn)得像值類(lèi)型,但從技術(shù)上講,它們?nèi)匀皇且妙?lèi)型。
由于字符串的不可變性,即使它們是引用類(lèi)型,修改一個(gè)字符串變量不會(huì)影響其他引用相同字符串的變量。這是因?yàn)楫?dāng)你修改字符串時(shí),實(shí)際上是創(chuàng)建了一個(gè)新的字符串對(duì)象,并將變量的引用指向了這個(gè)新對(duì)象。
string雖然方便,但是有一個(gè)小缺點(diǎn)就是頻繁的改變string重新賦值會(huì)產(chǎn)生內(nèi)存垃圾
,優(yōu)化替代方案我們會(huì)在后面進(jìn)行講解
專(zhuān)欄推薦
地址 |
---|
【從零開(kāi)始入門(mén)unity游戲開(kāi)發(fā)之——C#篇】 |
【從零開(kāi)始入門(mén)unity游戲開(kāi)發(fā)之——unity篇】 |
【制作100個(gè)Unity游戲】 |
【推薦100個(gè)unity插件】 |
【實(shí)現(xiàn)100個(gè)unity特效】 |
【unity框架開(kāi)發(fā)】 |
完結(jié)
贈(zèng)人玫瑰,手有余香!如果文章內(nèi)容對(duì)你有所幫助,請(qǐng)不要吝嗇你的點(diǎn)贊評(píng)論和關(guān)注
,你的每一次支持
都是我不斷創(chuàng)作的最大動(dòng)力。當(dāng)然如果你發(fā)現(xiàn)了文章中存在錯(cuò)誤
或者有更好的解決方法
,也歡迎評(píng)論私信告訴我哦!
好了,我是向宇
,https://xiangyu.blog.csdn.net
一位在小公司默默奮斗的開(kāi)發(fā)者,閑暇之余,邊學(xué)習(xí)邊記錄分享,站在巨人的肩膀上,通過(guò)學(xué)習(xí)前輩們的經(jīng)驗(yàn)總是會(huì)給我很多幫助和啟發(fā)!如果你遇到任何問(wèn)題,也歡迎你評(píng)論私信或者加群找我, 雖然有些問(wèn)題我也不一定會(huì),但是我會(huì)查閱各方資料,爭(zhēng)取給出最好的建議,希望可以幫助更多想學(xué)編程的人,共勉~