zoukankan      html  css  js  c++  java
  • 类型,对象,堆栈和托管堆

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

     

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

    先举个例子,有如下两个方法,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

    }

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

    上述的每个图片,基本对应程序中的每个步骤。在开始执行Method_1的时候,先把value1压入堆栈顶,然后是value2,接下来的是调用方法Add,因为方法有两个参数是n1和n2,所以把n1和n2分别压入堆栈,因为此处是调用了一个方法,并且方法有返回值,所以这里需要保存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_A的Purpose方法,即不用变量car调用,也不用对象调用,而是用类名Car调用,因为静态方法会在类中分配内存的。如果用Car生成多个实例,静态成员只有一份,就是在类中,而不是在对象中。

  • 相关阅读:
    半主机模式和_MICROLIB 库
    工作中常用的git命令
    Mybatis延迟加载参数配置
    JUnit展示图形化测试结果
    可读、可维护、可扩展,原则、模式与重构
    乐观锁和悲观锁
    HashMap实现原理和底层数据结构?
    视图有啥用?
    单例模式常见有哪几种?
    RPC服务和HTTP服务的区别
  • 原文地址:https://www.cnblogs.com/shiguangshuo/p/4857203.html
Copyright © 2011-2022 走看看