最近偶然看到这个博客你必须知道的.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 - 1.继承的本质的更多相关文章

  1. 个人理解java的继承

    java的类是属于单继承的.在继承这一块上我本来有一个很大的误区,就是觉得父类中private定义的成员无法被继承.直到网上的大神给我指出private是可以被继承的,会在内存中,只是在子类的对象中不 ...

  2. 彻底理解Javascript原型继承

    彻底理解Javascript原型继承 之前写过一篇Javascript继承主题的文章,这篇文章作为一篇读书笔记,分析的不够深入. 本文试图进一步思考,争取彻底理解Javascript继承原理 实例成员 ...

  3. 【CUDA 基础】3.2 理解线程束执行的本质(Part I)

    title: [CUDA 基础]3.2 理解线程束执行的本质(Part I) categories: CUDA Freshman tags: 线程束分化 CUDA分支 toc: true date: ...

  4. c++ 基础知识回顾 继承 继承的本质就是数据的copy

    c++ 基础知识笔记 继承 什么是继承 继承就是子类继承父类的成员属性以及方法 继承的本质就是 数据的复制 是编译器帮我们做了很多操作 class Base { public: Base(){ cou ...

  5. 从一些简单代码实例彻底理解面向对象编程思想|OOP本质是什么?

    从Rob Pike 的 Google+上的一个推看到了一篇叫<Understanding Object Oriented Programming>的文章,我先把这篇文章简述一下,然后再说说 ...

  6. java四大特性理解(封装继承多态抽象)

    封装: 封装是把过程和数据包围起来,对数据的访问只能通过已定义的接口.面向对象计算始于这个基本概念,即现实世界可以被描绘成一系列完全自治.封装的对象,这些对象通过一个受保护的接口访问其他对象.封装是一 ...

  7. 27、理解js的继承机制(转载自阮一峰)

    Javascript继承机制的设计思想   作者: 阮一峰 日期: 2011年6月 5日 我一直很难理解Javascript语言的继承机制. 它没有"子类"和"父类&qu ...

  8. c++父类指针强制转为子类指针后的测试(帮助理解指针访问成员的本质)(反多态)

    看下面例子: #include "stdafx.h" #include <iostream> class A {  //父类 public: void  f()   / ...

  9. 理解oo:继承、多态、重写、重载、接口、抽象类

    1. 继承: 从多个子类中抽象出实例变量以及方法,形成更抽象的父类,避免在子类中的代码重复,维护起来更加方便.检查是否可以使用继承技术的方法是:IS A 对于类A继承自类B,类C继承自类A,那么类C和 ...

随机推荐

  1. 【Python】 xml转json

    虽然python有解析xml的模块,也有生成json的模块,但是没有把这两者连接起来的模块. 下面是以来自MIT的大神Martin Blech写的一个方便的模块,供大家参考.也别忘了在用之前先拜谢作者 ...

  2. 如何从零开始学习区块链技术——推荐从以太坊开发DApp开始

    很多人迷惑于区块链和以太坊,不知如何学习,本文简单说了一下学习的一些方法和资源. 一. 以太坊和区块链的关系 从区块链历史上来说,先诞生了比特币,当时并没有区块链这个技术和名词,然后业界从比特币中提取 ...

  3. C语言程序设计(基础)- 第3周作业

    一.PTA编程题目 完成PTA第三周作业中4个题目: 1.7-9 A乘以B 要求:输入的两个整数:A是你学号前两位数字,B是你学号后两位数字 2.7-10 求整数均值 要求:输入的整数是:你的身高.体 ...

  4. bug终结者 团队作业第二周

    bug终结者 团队作业第二周 我们小组选取游戏"开心消消乐",回答问题: 1. 此类软件是什么时候开始出现的, 这些软件是怎么说服你(陌生人)成为他们的用户的? 他们的目标都是盈利 ...

  5. C程序设计-----第1次作业

    一. PTA作业.    在完成PTA作业的时候我没有认真读题.每次都是提交完整代码 6-1(1) #include <stdio.h> //P++等价于(p)++还是等价于*(p++)? ...

  6. vim配置之taglist插件安装

    上次说了不带插件的vim配置,今天补充两个,来日方长,不定期更新: 首先看一个路径: 下载ctags,将其中的ctags.exe复制到上边目录下边: 地址:https://sourceforge.ne ...

  7. 基于scrapy爬虫的天气数据采集(python)

    基于scrapy爬虫的天气数据采集(python) 一.实验介绍 1.1. 知识点 本节实验中将学习和实践以下知识点: Python基本语法 Scrapy框架 爬虫的概念 二.实验效果 三.项目实战 ...

  8. Scrum 冲刺 第五日

    目录 要求 项目链接 燃尽图 问题 今日任务 明日计划 成员贡献量 要求 各个成员今日完成的任务(如果完成的任务为开发或测试任务,需给出对应的Github代码签入记录截图:如果完成的任务为调研任务,需 ...

  9. xcode7,ios9 部分兼容设置

    神奇的苹果公司,再一次让程序员中枪. 一.xcode7 新建的项目,Foundation下默认所有http请求都被改为https请求. HTTP+SSL/TLS+TCP = HTTPS 也就是说,服务 ...

  10. NetFPGA Demo ——reference_router_nf1_cml

    NetFPGA Demo --reference_router_nf1_cml 前言 本博文主要介绍了reference_router_nf1_cml该demo的一路运行,以及一路上艰难跑通遇到的坑. ...