首先呢盒犹,關(guān)于值類型與引用類型在內(nèi)存布局存儲方面的不同之處:
對于內(nèi)存,我們?nèi)藶榈膶⑵浞譃榱宋宕蟛糠郑?br>
1眨业、BSS段:通常是指用來存放程序中未初始化的全局變量的一塊內(nèi)存區(qū)域急膀。BSS是英文Block Started by Symbol的簡稱。BSS段屬于靜態(tài)內(nèi)存分配龄捡。
2卓嫂、數(shù)據(jù)段:通常是指用來存放程序中已初始化的全局變量的一塊內(nèi)存區(qū)域。數(shù)據(jù)段屬于靜態(tài)內(nèi)存分配聘殖。
3晨雳、代碼段:通常是指用來存放程序執(zhí)行代碼的一塊內(nèi)存區(qū)域行瑞。這部分區(qū)域的大小在程序運(yùn)行前就已經(jīng)確定,并且內(nèi)存區(qū)域通常屬于只讀, 某些架構(gòu)也允許代碼段為可寫餐禁,即允許修改程序血久。在代碼段中,也有可能包含一些只讀的常數(shù)變量帮非,例如字符串常量等氧吐。
4、堆(heap):堆是用于存放進(jìn)程運(yùn)行中被動態(tài)分配的內(nèi)存段喜鼓,它的大小并不固定副砍,可動態(tài)擴(kuò)張或縮減。
5庄岖、棧 (stack):棧又稱堆棧豁翎, 是用戶存放程序臨時創(chuàng)建的局部變量,也就是說我們函數(shù)括弧“{}”中定義的變量(但不包括static聲明的變量隅忿,static意味著在數(shù)據(jù)段中存放變量)心剥。除此以外,在函數(shù)被調(diào)用時背桐,其參數(shù)也會被壓入發(fā)起調(diào)用的進(jìn)程棧中优烧,并且待到調(diào)用結(jié)束后,函數(shù)的返回值也會被存放回棧中链峭。由于棧的先進(jìn)先出特點(diǎn)畦娄,所以棧特別方便用來保存/恢復(fù)調(diào)用現(xiàn)場。從這個意義上講弊仪,我們可以把堆椢蹩ǎ看成一個寄存、交換臨時數(shù)據(jù)的內(nèi)存區(qū)励饵。
通常說的五大區(qū)為:
1驳癌、棧區(qū)(stack)— 由編譯器自動分配釋放 ,存放函數(shù)的參數(shù)值役听,局部變量的值等颓鲜。其操作方式類似于數(shù)據(jù)結(jié)構(gòu)中的棧。
2典予、堆區(qū)(heap) — 一般由程序員分配釋放甜滨, 若程序員不釋放,程序結(jié)束時可能由OS回收 瘤袖。注意它與數(shù)據(jù)結(jié)構(gòu)中的堆是兩回事
3艳吠、全局區(qū)(靜態(tài)區(qū))(static)—,全局變量和靜態(tài)變量的存儲是放在一塊的孽椰,初始化的全局變量和靜態(tài)變量在一塊區(qū)域昭娩, 未初始化的全局變量和未初始化的靜態(tài)變量在相鄰的另一塊區(qū)域凛篙。 - 程序結(jié)束后有系統(tǒng)釋放
4、文字常量區(qū) —常量字符串就是放在這里的栏渺。 程序結(jié)束后由系統(tǒng)釋放
5呛梆、程序代碼區(qū)—存放函數(shù)體的二進(jìn)制代碼。
而程序猿經(jīng)常用到的有三個區(qū):棧區(qū)磕诊,堆區(qū)填物、以及靜態(tài)區(qū)
我們用 堆 棧 存儲數(shù)據(jù),用靜態(tài)區(qū)存儲靜態(tài)數(shù)據(jù)
值類型的值存儲在棧中霎终,引用類型的值存儲在堆中
值類型: int double char decimal bool enum struct
引用類型:string 數(shù)組 自定義類 集合 object interface
關(guān)于值類型的傳遞與引用類型的傳遞:對于值類型傳遞滞磺,其傳遞的是值本身。對于引用類型傳遞莱褒,其傳遞的是值在堆中的地址击困。但是對于string類型而言,每次創(chuàng)建新對象都會開辟一塊新的內(nèi)存广凸,所以說阅茶,對于引用類型的傳遞不使用于string類型,即便string類型也是引用類型谅海,這是因為字符串的不可變性
在數(shù)據(jù)傳遞中脸哀,有兩個關(guān)鍵字需要注意一下:
關(guān)于 ref 關(guān)鍵字:ref
關(guān)鍵字通過引用(而非值)傳遞參數(shù)。 通過引用傳遞的效果是扭吁,對所調(diào)用方法中的參數(shù)進(jìn)行的任何更改都反映在調(diào)用方法中撞蜂。
不要混淆通過引用傳遞的概念與引用類型的概念。 這兩種概念是不同的侥袜。 無論方法參數(shù)是值類型還是引用類型蝌诡,均可由 ref修改。
當(dāng)通過引用傳遞時系馆,不會對值類型裝箱。
若要使用 ref參數(shù)顽照,方法定義和調(diào)用方法均必須顯式使用 ref關(guān)鍵字 .
傳遞到 ref形參的實參必須先經(jīng)過初始化由蘑,然后才能傳遞。 這與 out形參不同代兵,在傳遞之前尼酿,不需要顯式初始化該形參的實參。
如果對類的函數(shù)進(jìn)行重載植影,那么兩者不能僅僅是只在ref和out方面具有不同的簽名裳擎,如果類型的兩個成員之間的唯一區(qū)別在于其中一個具有 ref參數(shù),而另一個具有 out參數(shù)思币,則會發(fā)生編譯錯誤鹿响。但是羡微,當(dāng)一個方法有 ref或 out參數(shù),另一個方法具有值參數(shù)時惶我,則可以完成重載
對值類型使用ref關(guān)鍵字:
class RefExample
{
static void Method(ref int i)
{
i = i + 44;
}
static void Main()
{
int val = 1;
Method(ref val);
Console.WriteLine(val);
// Output: 45
}
}
對引用類型使用ref關(guān)鍵字:
class RefExample2
{
static void ChangeByReference(ref Product itemRef)
{
itemRef = new Product("Stapler", 99999);
itemRef.ItemID = 12345;
}
static void Main()
{
Product item = new Product("Fasteners", 54321);
System.Console.WriteLine("Original values in Main. Name: {0}, ID: {1}\n",
item.ItemName, item.ItemID);
ChangeByReference(ref item);
System.Console.WriteLine("Back in Main. Name: {0}, ID: {1}\n",
item.ItemName, item.ItemID);
}
}
class Product
{
public Product(string name, int newID)
{
ItemName = name;
ItemID = newID;
}
public string ItemName { get; set; }
public int ItemID { get; set; }
}
// Output:
//Original values in Main. Name: Fasteners, ID: 54321
//Back in Main. Name: Stapler, ID: 12345
其實妈倔,也就是說,ref是對參數(shù)的地址進(jìn)行操作的绸贡,如果參數(shù)是值類型盯蝴,那么就針對參數(shù)在棧上的地址(值類型的值是在棧中,但是其對應(yīng)在棧中的位置是一個地址)听怕,如果是引用類型捧挺,那么就針對堆上的地址操作。
關(guān)于 out 關(guān)鍵字:out
關(guān)鍵字通過引用傳遞參數(shù)尿瞭。 這與 ref 關(guān)鍵字相似闽烙,只不過 ref要求在傳遞之前初始化變量。
若要使用 out參數(shù)筷厘,方法定義和調(diào)用方法均必須顯式使用 out關(guān)鍵字鸣峭。
盡管作為 out參數(shù)傳遞的變量無需在傳遞之前初始化,調(diào)用方法仍要求在方法返回之前賦值
盡管 ref和 out關(guān)鍵字會導(dǎo)致不同的運(yùn)行時行為酥艳,它們并不被視為編譯時方法簽名的一部分摊溶。 因此,如果唯一的不同是一個方法采用 ref參數(shù)充石,而另一個方法采用 out參數(shù)莫换,則無法重載這兩個方法。
class OutExample
{
static void Method(out int i)
{
i = 44;
}
static void Main()
{
int value;
Method(out value);
// value is now 44
}
}
也就是說骤铃,其實out和ref的用法是類似的拉岁,但是ref需要參數(shù)在傳遞之前初始化,而out不用初始化惰爬,但是out需要在函數(shù)執(zhí)行過程中對參數(shù)進(jìn)行賦值
關(guān)于裝箱和拆箱:
什么是裝箱:
裝箱就是將值類型轉(zhuǎn)換為引用類型
什么是拆箱:
拆箱就是將引用類型轉(zhuǎn)換為值類型通常喊暖,
我們都是將值類型轉(zhuǎn)換為object,object不止是所有類型的基類撕瞧,它也是引用類型陵叽,比如:在ArrayList這個集合中,我們Add的時候丛版,存入的就是object類型巩掺,也就是會進(jìn)行裝箱操作。
但是頻繁的裝箱和拆箱對性能會造成損耗页畦,而且還會拖慢程序執(zhí)行的時間
關(guān)于序列化與反序列化
什么是序列化胖替?
序列化就是將對象轉(zhuǎn)換為二進(jìn)制
什么是反序列化?
反序列化就是將二進(jìn)制轉(zhuǎn)換為對象
作用:傳輸數(shù)據(jù)(在網(wǎng)絡(luò)傳輸中,傳送的都是二進(jìn)制)
如何將對象轉(zhuǎn)換為二進(jìn)制独令?
首先你要將對象所屬的類標(biāo)記為[System.Serializalbe]
然后可以用BinaryFormatter類的對象端朵,對其進(jìn)行序列化
BinaryFormatter是屬于System.IO命名空間下的一個針對二進(jìn)制文件的類
比如,我們創(chuàng)建一個對象:BinaryFormatter bf = new BinaryFormatter();
然后记焊,我們就可以調(diào)用 bf.Serialize()這個方法來進(jìn)行序列化
還可以調(diào)用 bf.Deserialize()來進(jìn)行反序列化逸月,
不過在反序列的時候,該方法會返回一個object類型的對象遍膜,我們需要進(jìn)行拆箱操作碗硬,將其強(qiáng)轉(zhuǎn)成我們需要的類型對象。