现在的位置: 首页 > 综合 > 正文

.net知识和学习方法系列(十五)类型,对象,堆栈和托管堆

2012年05月19日 ⁄ 综合 ⁄ 共 2057字 ⁄ 字号 评论关闭
 

1、          类型,对象,堆栈和托管堆

C#的类型和对象在应用计算机内存时,大体用到两种内存,一个叫堆栈,另一个叫托管堆,下面我们用直角长方形来代表堆栈,用圆角长方形来代表托管堆。

 

 

首先讨论一下方法内部变量的存放。

先举个例子,有如下两个方法,Method_1Add,分别如下:

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

}

这段代码的执行,用图表示为:

 

上述的每个图片,基本对应程序中的每个步骤。在开始执行Method_1的时候,先把value1压入堆栈顶,然后是value2,接下来的是调用方法Add,因为方法有两个参数是n1n2,所以把n1n2分别压入堆栈,因为此处是调用了一个方法,并且方法有返回值,所以这里需要保存Add的返回地址,然后进入Add方法内部,在Add内部,首先是给sum赋值,所以把sum压入栈项,然后用return返回,此时,先前的返回地址就起到了作用,return会根据地址返回去的,在返回的过程中,把sum推出栈顶,找到了返回地址,但在Method_1方法中,我们希望把Add的返回值赋给value3,此时的返回地址也被推出堆栈,把value3压入堆栈。虽这个例子的结果在这里没有多大用途,但这个例子很好的说明了在方法被执行时,变量与进出堆栈的情况。这里也能看出为什么方法内部的局变量用过后,不能在其他方法中访问的原因。

 

其次来讨论一下类和对象在托管堆和堆栈中的情况。

先看一下代码:

    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;

        }

}

上面是两个类,一个Father一个Son,Son继承了Father,因为你类中有一个virtual的BuyHouse方法,所以Son类可以重写这个方法。

下面接着看调用代码。

        public void Method_A()

        {

            double CarPrice;//1

            Car car = new BMW();//2

            CarPrice = car.GetPrice();//调用虚方法(其实调用的是重写后的方法)

            car.Run();//调用实例化方法

            Car.Purpose();//调用静态方法

 }

这个方法也比较简单,就是定义一个变量用来获得价格,同时定义了一个父类的变量,用子类来实例化它。

接下来,我们分步来说明。

看一下运行时堆栈和托管堆的情部我:

 

这里需要说明的是,类是位于托管堆中的,每个类又分为四个类部,类指针,用来关联对象;同步索引,用来完成同步(比如线程的同步)需建立的;静态成员是属于类的,所以在类中出现,还有一个方法列表(这里的方法列表项与具体的方法对应)。

Method_A方法的第一步执行时: 

 这时的CarPrice是没有值的

Method_A方法执行到第二步,其实第二步又可以分成

Car car;

 car = new BMW();

先看Car car;

 


car在这里是一个方法内部的变量,所以被压到堆栈中。

 再看 car = new BMW();

这是一个实例化过程,car变成了一个对象

 

 


这里是用子类来实例化父类型。对象其实是子类的类型的,但变量的类型是父类的。

接下来,在Method_A中的调用的中调用car.GetPrice(),对于Car来说,这个方法是虚方法(并且子类重写了它),虚方法在调用是不会执行类型上的方法,即不会执行Car类中的虚方法,而是执行对象对应类上的方法,即 BMW中的GtPrice

如果Method_A中执行方法Run(),因为Run是普通实例方法,所以会执行Car类中的Run方法。

如果调用了Method_APurpose方法,即不用变量car调用,也不用对象调用,而是用类名Car调用,因为静态方法会在类中分配内存的。如果用Car生成多个实例,静态成员只有一份,就是在类中,而不是在对象中。

【上篇】
【下篇】

抱歉!评论已关闭.