1、 類型,對(duì)象,堆棧和托管堆
C#的類型和對(duì)象在應(yīng)用計(jì)算機(jī)內(nèi)存時(shí),大體用到兩種內(nèi)存,一個(gè)叫堆棧,另一個(gè)叫托管堆,下面我們用直角長(zhǎng)方形來(lái)代表堆棧,用圓角長(zhǎng)方形來(lái)代表托管堆。
首先討論一下方法內(nèi)部變量的存放。
先舉個(gè)例子,有如下兩個(gè)方法,Method_1和Add,分別如下:
public void Method_1()
{
int value1=10; //1
int value2=20; //2
int value3=Add(value,value); //3
}
public int Add(int n1,int n2)//4
{
rnt sum=n1+n2;//5
return sum;//6
}
這段代碼的執(zhí)行,用圖表示為:
上述的每個(gè)圖片,基本對(duì)應(yīng)程序中的每個(gè)步驟。在開始執(zhí)行Method_1的時(shí)候,先把value1壓入堆棧頂,然后是value2,接下來(lái)的是調(diào)用方法Add,因?yàn)榉椒ㄓ袃蓚€(gè)參數(shù)是n1和n2,所以把n1和n2分別壓入堆棧,因?yàn)榇颂幨钦{(diào)用了一個(gè)方法,并且方法有返回值,所以這里需要保存Add的返回地址,然后進(jìn)入Add方法內(nèi)部,在Add內(nèi)部,首先是給sum賦值,所以把sum壓入棧項(xiàng),然后用return返回,此時(shí),先前的返回地址就起到了作用,return會(huì)根據(jù)地址返回去的,在返回的過(guò)程中,把sum推出棧頂,找到了返回地址,但在Method_1方法中,我們希望把Add的返回值賦給value3,此時(shí)的返回地址也被推出堆棧,把value3壓入堆棧。雖這個(gè)例子的結(jié)果在這里沒(méi)有多大用途,但這個(gè)例子很好的說(shuō)明了在方法被執(zhí)行時(shí),變量與進(jìn)出堆棧的情況。這里也能看出為什么方法內(nèi)部的局變量用過(guò)后,不能在其他方法中訪問(wèn)的原因。
其次來(lái)討論一下類和對(duì)象在托管堆和堆棧中的情況。
先看一下代碼:
class Car
{
public void Run()
{
Console.WriteLine("一切正常");
}
public virtual double GetPrice()
{
return 0;
}
public static void Purpose()
{
Console.WriteLine("載人");
}
}
class BMW : Car
{
public override double GetPrice()
{
return 800000;
}
}
上面是兩個(gè)類,一個(gè)Father一個(gè)Son,Son繼承了Father,因?yàn)槟泐愔杏幸粋€(gè)virtual的BuyHouse方法,所以Son類可以重寫這個(gè)方法。
下面接著看調(diào)用代碼。
public void Method_A()
{
double CarPrice;//1
Car car = new BMW();//2
CarPrice = car.GetPrice();//調(diào)用虛方法(其實(shí)調(diào)用的是重寫后的方法)
car.Run();//調(diào)用實(shí)例化方法
Car.Purpose();//調(diào)用靜態(tài)方法
}
這個(gè)方法也比較簡(jiǎn)單,就是定義一個(gè)變量用來(lái)獲得價(jià)格,同時(shí)定義了一個(gè)父類的變量,用子類來(lái)實(shí)例化它。
接下來(lái),我們分步來(lái)說(shuō)明。
看一下運(yùn)行時(shí)堆棧和托管堆的情部我:
這里需要說(shuō)明的是,類是位于托管堆中的,每個(gè)類又分為四個(gè)類部,類指針,用來(lái)關(guān)聯(lián)對(duì)象;同步索引,用來(lái)完成同步(比如線程的同步)需建立的;靜態(tài)成員是屬于類的,所以在類中出現(xiàn),還有一個(gè)方法列表(這里的方法列表項(xiàng)與具體的方法對(duì)應(yīng))。
當(dāng)Method_A方法的第一步執(zhí)行時(shí):
當(dāng)Method_A方法執(zhí)行到第二步,其實(shí)第二步又可以分成
Car car;
car = new BMW();
先看Car car;
car在這里是一個(gè)方法內(nèi)部的變量,所以被壓到堆棧中。
再看 car = new BMW();
這是一個(gè)實(shí)例化過(guò)程,car變成了一個(gè)對(duì)象
這里是用子類來(lái)實(shí)例化父類型。對(duì)象其實(shí)是子類的類型的,但變量的類型是父類的。
接下來(lái),在Method_A中的調(diào)用的中調(diào)用car.GetPrice(),對(duì)于Car來(lái)說(shuō),這個(gè)方法是虛方法(并且子類重寫了它),虛方法在調(diào)用是不會(huì)執(zhí)行類型上的方法,即不會(huì)執(zhí)行Car類中的虛方法,而是執(zhí)行對(duì)象對(duì)應(yīng)類上的方法,即 BMW中的GtPrice。
如果Method_A中執(zhí)行方法Run(),因?yàn)?/span>Run是普通實(shí)例方法,所以會(huì)執(zhí)行Car類中的Run方法。
如果調(diào)用了Method_A的Purpose方法,即不用變量car調(diào)用,也不用對(duì)象調(diào)用,而是用類名Car調(diào)用,因?yàn)殪o態(tài)方法會(huì)在類中分配內(nèi)存的。如果用Car生成多個(gè)實(shí)例,靜態(tài)成員只有一份,就是在類中,而不是在對(duì)象中
聯(lián)系客服