1、 類型,對(duì)象,堆棧和托管堆 C#的類型和對(duì)象在應(yīng)用計(jì)算機(jī)內(nèi)存時(shí),大體用到兩種內(nèi)存,一個(gè)叫堆棧,另一個(gè)叫托管堆,下面我們用直角長方形來代表堆棧,用圓角長方形來代表托管堆。
首先討論一下方法內(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,接下來的是調(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ù)地址返回去的,在返回的過程中,把sum推出棧頂,找到了返回地址,但在Method_1方法中,我們希望把Add的返回值賦給value3,此時(shí)的返回地址也被推出堆棧,把value3壓入堆棧。雖這個(gè)例子的結(jié)果在這里沒有多大用途,但這個(gè)例子很好的說明了在方法被執(zhí)行時(shí),變量與進(jìn)出堆棧的情況。這里也能看出為什么方法內(nè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è)方法也比較簡單,就是定義一個(gè)變量用來獲得價(jià)格,同時(shí)定義了一個(gè)父類的變量,用子類來實(shí)例化它。 接下來,我們分步來說明。 看一下運(yùn)行時(shí)堆棧和托管堆的情部我:
這里需要說明的是,類是位于托管堆中的,每個(gè)類又分為四個(gè)類部,類指針,用來關(guān)聯(lián)對(duì)象;同步索引,用來完成同步(比如線程的同步)需建立的;靜態(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í)例化過程,car變成了一個(gè)對(duì)象
這里是用子類來實(shí)例化父類型。對(duì)象其實(shí)是子類的類型的,但變量的類型是父類的。 接下來,在Method_A中的調(diào)用的中調(diào)用car.GetPrice(),對(duì)于Car來說,這個(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ì)象中 |
|