• 第四章 类型基础


    这章不好理解,我是连抄带找的。。。。。。。。。。。

    一、System.Object

      所有类型的基类,也就是所有类型从它派生。 公开了几个方法:

    1. Equals : 判定两个对象是否具有相同的值(相等性和同一性后续讨论
    2. GetHashCode
    3. ToString() 默认返回类型的完整名称,但是经常会重写返回表示对象状态的string。例如:int32 toString() 显示字段的值
    4. GetType:返回从type派生的一个类型的实例,调用的对象是什么类型。
    5. MemberwsiseClone: 深度拷贝
    6. Finalize : 在垃圾回收器判定对象是垃圾后,在对象的内存被实际回收之前,调用这个虚方法。需要在回收内存之气那执行新区管理工作的类型应该重写该方法。顺便说下:Finalize是会先执行父类Finalize 如果父类Finalize执行后,子类再执行Finalize时候会引发异常。具体后面介绍。

    二、new 关键字

    Dog  dog= new Dog(“旺财”);

    作用

    1、计算类型及其所有基类型(一直到 System.Object )中定义的所有实例字段所需要的字节数。对象含有额外字节开销,(1.类型对象指针  2.同步索引快 )CLR利用这些成员管理对象。额外成员的字节数要计入对象的大小

    2、从托管堆中分配类型要求的字节数,从而分配对象的内存,分配的所有字节都设为零(0

    3、初始化对象的类型指针和同步索引成员

    4、调用类型的实例构造器,传递在new调用中指定的实参(eg:旺财)编译器都在构造器中自动生成代码来调用基类构造器 ,每个类型的构造器否负责初始化该类型定义的实例字段,最终调用System.Object的构造器。因为没有定义任何实例字段所以该构造器什么都不做,直接返回。

    三、类型转换 is  as

      1、类型转化规则: 子类可以直转为基类  public class Dog:Anmial{}

                     狗是动物, Anmial animal=new Dog();

     基类不能直接转化为子类

          Dog dog=new Animal(); (X) 可以这么理解编译器要做类型推断,但是呢动物不一定是狗还可能是人或者别的动物猫。另外,语法安全上也是要求不能直接从基类转为子类。

    2、is as

       类型需要转化通常我们会这样: 因此各自利弊自己选择

    void GetName(Anmial animal)

    {

      If(animal is Dog){  Dog dog=(Dog)animal ; xxx} //此处会做两次的类型检查 ,失败返回false

    }

    void GetName(Anmial animal)

    {

    Dog dog=animal as Dog; //此处会做一次次的类型检查 ,失败返回 null

          If(dog !=nul){  xxx }

    }

    四、运行时的相互关系

    1. 简单方法的调用需要预先知道的术语:

     A:进程、线程(后面章节详细介绍)

     B:线程栈:CLR创建线程时候会分配1M的栈空间,特点是从高位向地位地址构建(这里有个原因大家想想为啥呢,为啥不是从地位向高位构建)

     C:压栈:方法的参数的地址将会以该形式进入线程栈

    序幕代码(开场):我也很无奈为啥翻译成这个名字, prologue

      开始执行方法前初始化变量,在栈上分配内存

    尾声代码(后记):我也很无奈为啥翻译成这个名字, epilogue

     执行完后清理内存并且返回到调用者。

    程序执行开始后,加载一个CLR的一个windows进程,进程有多个线程。线程创建时候会分配到1M的栈,栈空间用于向方法传递实参,实参,实参,方法内部定义的局部变量也在栈上,栈上已经有了一些数据了(顶部阴影)。现在执行到了M3的方法。

    执行M3时候,CLR会初始化M3的方法,包括开场代码和结束代码,开场代码用来初始化局部变量并且分配内存,引用类型指向null,值类型设置为0.

    1.运行时-值类型的分配和方法调用

    图中3的返回地址是在M3中调用执行M2的时候,压栈进去的,目的是告诉调度指针执行完M2的时候记得返回这里,执行M2的时候类似的分配空间,执行完M2之后 45将会被结束代码(CLR叫做尾声代码,这什么鬼翻译!)清除掉,专业术语叫做 栈针unwind行为,同时栈针指向3继续执行,当执行完M3时候同样重复清除,栈针指向调用M3的返回地址,(该地址在 线程栈0位置下方,1位置上方一点)这样就结束了方法调用。

    有了这些基本知识接下来我们看下堆上的变化情况:先看下一段代码

     

    同理要分配一个线程栈,调用方法前,有个序幕代码、和尾声代码。行为和上面讲到的一致。

    1. 运行时-引用类型和方法的调用

    此处我们更关注堆上的变化

    当执行到 new的关键字作用:结算对象占用内存大小(对象的类型指针大小,同步索引快、局部变量、基类类型消耗的字段等一直计算到Object)之后上形成如图:

     

    17行代码执行完毕后形成如下图示:结合代码部分注释和下图理解运行时和方法的调用。

     

    Type类型对象:所有类型对象的基类,它的类型对象指针指向自己。

     现在解释下 你方法中的的GetType() 时候自己没有定义为什么能调用到,开始我们讲了这个呢是基类的Object的非虚方法 GetType(),而且图中的Dog类型对象 Animal类型对象,都是Type的一个实例,因此就知道了你调用的对象的实际类型。(具体怎么知道?看下面解释)

        类型本质上也是对象,CLR创建类型对象时,必须初始化以上类型在分配时包含的成员,初始化成什么呢?CLR开始在一个进程中运行时,会立即为强命名程序集MSCorLib.dll中定义的System.Type类型创建一个特殊的类型对象。

    而我们自定义的用户类型都是该类型的实例。也就是对象指针指向 Type类型对象。

       当我们调用GetType()是时候返回的是:存贮在特定类型对象上的成员的地址指针。

       这个怎么理解呢就是你调用Dog.GetType()返回的是存贮在Type类型上的对象类型指针地址,

       即Dog类型对象指针,返回了Dog类型对象指针自然就知道了Dog是什么类型了。

    对象类型指针和同步索引快、字段空间、方法地址空间=套餐。以后以套餐相称

  • 相关阅读:
    6.1 tar:打包备份
    6.3-4 zip、unzip
    6.5 scp:远程文件复制
    S7 Linux用户管理及用户信息查询命令
    7.6 passwd:修改用户密码
    7.2-5 usermod
    DES
    FreeRTOS笔记
    第4章 裸机系统和多任务系统
    第008课_第1个ARM落版程序及引申
  • 原文地址:https://www.cnblogs.com/LiMin/p/10785536.html
Copyright © 2020-2023  润新知