程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#基礎知識 >> C#基礎之內存分配

C#基礎之內存分配

編輯:C#基礎知識

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();
    }
View Code
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("學生  在跑步");
        }
    }
View Code

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("人說:你好!");
        }
    }
View Code
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("學生  在跑步");
        }
    }
View Code
 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說:你好!");
        }
    }
View Code

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved