明月轻轻叹了口气”昨晚丈夫说他有可能会亲自出征,这让她心中又牵挂起来,才回来几个月,又要出征了吗?

深入理解.net - 1.继承的本质


最近偶然看到这个博客你必须知道的.net,作者6的飞起啊,干货十足,还是07年写的。。。写的也很赞,评论更精彩,在此强烈推荐一波,看的感觉就像沙漠里发现了绿洲一样,很兴奋,意犹未尽,迫不及待的看完一篇再看下一篇,但是知识还是需要整理,沉淀的,那就写博客吧,于是有了接下来的文章。本文将通过看此书和相关博客以及结合自己目前的理解所写,如有不对之处,欢迎指正。

对象的创建过程

要了解继承的本质首先我们要清楚一个对象的创建过程,这里有个 Chicken 类:

public class Chicken 
{
    private  string type = "Chicken";
    
    public Chicken()
    {
    }
    
    public void ShowType()
    {            
        Console.WriteLine($"Type is {type}");
    }
}

当我们需要使用这个类的时候,我们通常是这样写的:

Chicken chicken = new Chicken(); 

它是如何工作的呢?先上图:

具体过程如下:

  1. 首先执行的是 "Chicken chicken" 语句,即线程栈Stack上声明了一个Chicken类型的引用chicken,此时值为null,Stack上内存分配由高到低地址开始创建, 而Heap上则相反;
  2. 执行 "new Chicken()" ,new 操作符会在托管堆(具体在GCH:Garbage Collection Heap)上申请创建实例的内存空间,初始化类的字段(Feild)信息,并调用构造函数。结合上图,实例在GCHeap创建的详细过程如下:
    • 对象实例地址的开始4个字节为SyncBlockIndex,指向SyncEntryTable,存储的是多线程同步的一些信息,详细内容可查看文章末尾参考连接;
    • 紧接着是TypeHandle,指向的是Loader Heap(加载器堆) 中的MethodTable,而MethodTable中存储该类型的静态字段,方法表以及实现的接口等信息,从这里我们也就清楚了,一个类不管实例成员有多少,static成员和方法信息只存储一份在内存中,并先于实例创建,使用的时候则通过TypeHandle到MethodTable查找,并编译成cpu指令,存储在内存中,以后再使用时则直接执行该指令即可。
    • 初始完SyncBlockIndex和TypeHandle,则加载Chicken类型的字段信息,本文初始的也就是type字段(字符串信息的存储比较特殊实际存储模型详见此链接),另外强调的是属性不在此处初始,属性本质上还是 **_Get/**_Set方法;
    • 初始完字段后,则调用构造函数Chicken(),并返回this。

3.最后将this赋值给Stack上的chicken引用类型,即chicken维护一个指向heap上Chicken实例的指针,实际stact上的chicken存储的是GCHeap上实例存储的地址;

继承的本质

如果你看到这里,那说明你已经对一个对象的创建过程有了清晰的认识。回归主题那继承的本质是什么?先别急,下面我们写一个 Animal 类,让上文中的Chicken类继承它,并重写父类中的ShowType方法,本示例代码参考书中示例略微有所调整代码如下:

public class Animal 
{
    private string type ="Animal";

    public Animal()
    {

    }

    public virtual void ShowType()
    {
        Console.WriteLine($"Type is {type}");
    }
}
public class Chicken : Animal
{
    public string type = "Chicken";

    public Chicken()
    {
    }
    
    public override void ShowType()
    {            
        Console.WriteLine($"Type is {type}");
    }
    
}

那么这个时候我们去执行 Chicken chicken = new Chicken(); 发生了什么呢?

根据上图我们可以很直观的看出(此处暂时不考虑Object):

  1. 首先会先初始化chicken.type 字段,然后调用Chicken 构造函数;
  2. 此时编译器发现还有父类则去为父类Animal 申请内存,即初始Animal.type 字段,然后调用Animal的构造函数;因为所有类型都是继承自System.Object 所以实际上会一直遍历到Object类型;此外从这个过程中我们也可以发现子类是可以继承父类私有成员信息,即chicken可以继承Animal的type字段,字段存储顺序是父类在前子类在后,跟踪截图如下:
  3. Animal()方法体执行完后,然后在执行Chicken()的方法体。
  4. 此处额外说下关于方法的加载,在继承过程子类会将父类中的方法copy一份,并将重写的方法覆盖掉父类中的方法,这也就为多态提供了基础。

最后

写这篇博客参考了不少其它牛人的博客,发现关于这块往深里东西还有很多,如AppDomain应用程序域,ManagerHeap可以分多种不同的类型,GC对不同的Heap处理规则也是不同的,近期也会持续分享相关内容。写博文期间内容也不断反复调整了几轮,希望在此我都表达清楚了,限于篇幅主要内容还是关于对象和继承的本质过程,内容基本上也都是根据自己的理解写出来的,难免有疏漏的地方,如有不对的对方还请指出,那将是我不断进步的源泉:-)。

参考

  • 《你必须知道的.net(第2版)》 - 王涛
  • 你必须知道的.net博客目录:http://www.cnblogs.com/anytao/archive/2007/09/14/must_net_catalog.html - 王涛
  • 类型实例的创建位置、托管对象在托管堆上的结构 - Silent Void
  • 关于CLR内存管理一些深层次的讨论下篇 - Artech

当前文章:http://hnhdqp.com/R/12725.html

发布时间:2018-10-24 00:00:00

日赚50的手机软件 手机兼职平台71团 校园兼职代理 事业单位人员兼职 手机兼职应用试玩骗局 我想在家做网络兼职 costa兼职要求 适合女人做的副业生意 做任务赚q币的网站 现今致富0元创业项目

编辑:秉伯

相关新闻

每个人都是“中国梦”的使者

2018-10-24 00:00:00

嘉兴沦前网络科技有限公司

TCL乐玩2是否会成为电信用户的换机首选?

2018-10-24 00:00:00

株洲磷已拥广告传媒有限公司

牌神莫问出处?条条大道通德扑!

2018-10-24 00:00:00

十堰似乖俣幼儿园

酒店的最后一间房的价格会比其他房间便宜一半?服务员告知真相

2018-10-24 00:00:00

四平切夏冈集团有限责任公司

热门推荐

  • 松下LUMIX G9微单评测:可拍摄8000万像素照片
  • 菊花茶金丝皇菊2盒36朵58→25元,普洱茶熟茶饼357g装108→28元
  • 比男朋友更暖:Yuasa Primes发热抱枕让你忘了他
  • 锤子坚果Pro2发布会回顾 :老罗这些金句你不能错过
  • 索尼新应用PlayLink将至 可用手机玩主机游戏
  • 深闺藏瑜璟,岂顾冷清洲?卓伟又写诗了不过这次的周一见太弱
  • 神车换“芯” 新款哈弗H6将于11月上市
  • 何挺被免去重庆副市长、市公安局局长职务
  • 首都机场受雷雨天气等影响 作废航班183架次
  • 这样的悬崖村,看一看腿都软!他们咋脱贫?
  • 河北新闻网版权所有 本站点信息未经允许不得复制或镜像 法律顾问:网络上赚钱的项目 2018赚钱游戏排行榜
  • 在家做手工赚钱项目 copyright ? 2000 - 2016
  • 新闻热线:0311-67563366 广告热线:0311-67562966 新闻投诉:0311-67562994
  • 冀ICP备 09047539号-1 | 互联网新闻信息服务许可证编号:1312006002
  • 广播电视节目制作经营许可证(冀)字第101号|信息网络传播视听节目许可证0311618号
  • 给小学生答题赚钱软件 用电脑可以做什么兼职 网上赚钱项目 在家干什么赚钱