1.建立一個對象
一個對象的建立過程主要分為記憶體配置和初始化兩個環節。在.NET中CLR管理的記憶體地區主要有三部分:棧、GC堆、LOH堆,棧主要用來分配實值型別資料。它的管理是有系統控制的,而不是像GC堆那樣是由GC控制的。當線程執行完實值型別執行個體所在方法後,這塊空間將會被自動釋放,一般棧的執行效率高不過容量有限。
GC堆用來分配小對象執行個體,它是由GC完全控制記憶體的分配和回收。LOH堆則是為大對象執行個體準備的,它不會被壓縮且只在GC完全回收時才會回收。在IL中可以看到newobj、ldstr(建立string對象)、newarr(用於分配新的數組對象)、box(裝箱)等常見的建立對象的指令。
當然在堆上也存在實值型別,比如實值型別作為類的欄位時,它將儲存在堆中的執行個體對象空間,還有裝箱時也會讓堆上存在實值型別。好了接下來我們來看看建立一個對象的記憶體配置,現在有一個Person類和Student類。那麼這句Student s = new Student() { studentId = 2, Id = 4 };執行完後s對象就被建立了,下面我畫了張圖來說明建立一個對象時記憶體的分配,其中s對象還有同步索引塊與類型對象指標我沒有畫出來。
public class Person { public int Id; public void Eat() { Console.WriteLine("Eat Pear"); } } public class Student:Person { public int studentId; public void GotoSchool() { Console.WriteLine("Go to School"); } }
View Code
2.父類對象指向子類
我們在寫程式時為了實現多態一般都會使用父類對象指向子類。那麼當我寫入Person p=new Student();時便在堆中建立了一個子類對象,下面是關於父類對象指向子類的記憶體配置圖。我在Person中添加了虛方法和抽象方法,並在Student子類重寫了方法。
可以看出一旦子類重寫了父類的虛方法或抽象方法,則Person方法表中的2個方法將會被子類覆蓋,我們可根據它來實現多態。另外在Student方法表中還有一個new void Eat()方法,不過它是無法被p調用的因為此時的new Eat()屬於子類。
也就是說除了被覆蓋的方法外,p只能調用Person方法表中的方法,如果找不到則會繼續尋找Person父類的方法直到object。注意是不會往回找的,它不會去Student方法表中尋找方法
public abstract class Person { public int Id; public void Eat() { Console.WriteLine( "在吃梨"); } public virtual void Walk() { Console.WriteLine("在散步"); } //抽象方法只能在抽象類別中聲明,因此要在Person前加abstract,且只能聲明並必須在子類中實現。 public abstract void Run(); }public class Student:Person { public int studentId; public void GotoSchool() { Console.WriteLine("Go to School"); } public new void Eat() { Console.WriteLine("學生 吃蘋果"); } public override void Walk() { Console.WriteLine("學生 在散步"); } public override void Run() { Console.WriteLine("學生 在跑步"); } }
3.指向孫類對象
現在我再添加一個Student的子類James,從上一個例子中已經知道只有override關鍵字重寫的方法父類才會調用,因此我將普通方法全部刪除。執行代碼為Person p = new James() { name = “James”, studentId = 2, Id = 4 };代碼和記憶體配置圖如下,為了突出重點,圖中我就沒有畫欄位了。從結果可以看到SayHi方法最後是被孫類的SayHi覆蓋了,從這裡可以看出繼承的傳遞性!
public abstract class Person { public int Id; public virtual void Eat() { Console.WriteLine( "在吃梨"); } public virtual void Walk() { Console.WriteLine("在散步"); } //抽象方法只能在抽象類別中聲明,因此要在Person前加abstract,且只能聲明並必須在子類中實現。 public abstract void Run(); public virtual void SayHi() { Console.WriteLine("人說:你好!"); } }public class Student:Person { public int studentId; public virtual void Eat() { Console.WriteLine("學生 在吃梨"); } public override void Walk() { Console.WriteLine("學生 在散步"); } public override void Run() { Console.WriteLine("學生 在跑步"); } }public class James:Student { public string name; public override void Eat() { Console.WriteLine("James 在吃梨"); } public override void Walk() { Console.WriteLine("James 在散步"); } public override void Run() { Console.WriteLine("James 在跑步"); } public override void SayHi() { Console.WriteLine("James說:你好!"); } }
以上就是C#基礎之記憶體配置的內容,更多相關內容請關注topic.alibabacloud.com(www.php.cn)!