构造函数你真的看懂了吗

转载 2016年08月28日 15:37:53

转载自:http://www.cnblogs.com/CreateMyself/p/4730049.html

看过我之前复习的随笔知道都是基础之上的语法,但是当我脑海开启回忆基础知识时,尤其是构造函数中先后执行顺序以及原因却是模棱两可,于是开始边编写边操笔来记叙下来。如果你正在学习基础语法或者是复习基础语法的路上,这篇文章或许对你亦有帮助(当然msdn也有相关定义,但是个人觉得要是看完定义后再去摸索下,或许会理解的更透彻吧)。【特此注意:高手请绕过道而走!】

继承之构造函数

 首先我们定义一个Person类,并给个构造函数。代码如下:

复制代码
    public class Person
    {

        public string Name { get; set; }

        public int Age { get; set; }

        public bool Gender { get; set; }

        public Person()
        {
            Console.WriteLine("父类构造函数");
        }
    }
复制代码

再写个Bob类继承该父类,同时给个构造函数,其代码如下:

复制代码
    public class Bob : Person
    {
        public Bob()
        {
            Console.WriteLine("子类构造函数");
        }
    }
复制代码

接下来就在控制台实例化Bob类  Bob b = new Bob(); 看调用构造函数先后执行顺序。结果输出如下:

从这输出来看你会不会妄下结论说先调用的父类构造函数再调用子类的构造函数呢?如果你这样说的话,也就是说当我们实例化对象子类时,但是它去执行了父类的构造函数,好像有点神奇。好吧,我们接下来继续看,我们再定义一个Student类继承该Bob类。代码如下:

复制代码
    public class Student : Bob {

        public Student() {
            Console.WriteLine("学生类构造函数");
        }
    }
复制代码

然后在控制台实例化Student类 Student s = new Student(); ,结果打印出:

依然是调用的父类构造函数,所以现在就下结论:子类继承父类,实例化子类对象,首先调用的是父类构造函数。好,结论似乎言之过早,我们来断点调试下不就可以得出答案所在了吗。 看下面图片,一步步断点截图:

第一步:不用说

第二步:调用子类构造函数即Bob类

第三步:调用父类构造函数即Person类

第四步:执行父类的构造函数

最后一步:执行子类构造函数

所以总结如下:子类继承父类时构造函数执行的先后顺序:

  1. 调用子类构造函数
  2. 调用父类构造函数
  3. 执行父类构造函数
  4. 执行子类构造函数 

 但是此时问题来了,为什么我们实例化子类对象时,最后去调用了父类的构造函数?其实是有道理可循的,我忘记了base关键字的存在,当你在子类编写构造函数时,如果没有显式的调用基类的构造函数,那么会默认在其后面添加 一个 :base() 以此来调用基类的无参构造函数。所以上述问题就解决了。

msdn上所说base关键字概念有两点:

  • 调用基类上已被其他方法重写的方法。

  • 指定创建派生类实例时应调用的基类构造函数。

接下来如果我们在父类中将无参构造函数修改为有参构造函数会怎样呢,这是我们再生成出现如下错误:

因为上面已经说的很清楚了,如果父类没有无参构造函数,但是子类默认会带调用父类无参的构造函数所以会出错。所以解决办法 就是在子类中构造函数显示的用 :base 来调用父类有参构造函数即可,具体不再演示。 

但是问题又来了:为什么要让父类构造函数优先于子类构造函数执行呢??????请看下面给出合理解释。

我们将整个代码进行整合如下来讨论下:

复制代码
    public class Person
    {

        public string Name { get; set; }

        public int Age { get; set; }

        public bool Gender { get; set; }

        public Person(string name,int age)
        {
            Console.WriteLine("父类构造函数");
        }
    }

    public class Bob : Person
    {
        public Bob(string name,int age):base(name,11)  (1)
        {
            this.Name = name;
            this.Age = age;
            Console.WriteLine("子类构造函数");
        }
    }

    
    class Program
    {
        static void Main(string[] args)
        {

            Bob b = new Bob("1",12); (2)
            Console.ReadKey();
        }
    }
复制代码

我们只需看上述代码中标记为红色的(1)和(2),如果我们现在实例化Bob类并传参 age = 12 ,此时我们当然希望的是Bob类中age = 12,如果此时先执行子类那完了,因为有 :base(name,11) ,所以此时的 age = 11 ,这样不就造成了意想不到的结果了吗,明明传的12,结果为11,结果数据产生严重的冲突,也就是数据的不一致。如果先执行父类构造函数,此时子类age为11,但是当执行到子类构造函数时,因为我传的是12所以其age就为12。这才是我们需要的结果。

静态构造函数 

 我们继续就上述例子中的Person类为例进行分析,代码如下:

复制代码
    public class Person
    {

        public string Name { get; set; }

        public int Age { get; set; }

        public bool Gender { get; set; }

        public Person()
        {
            Console.WriteLine("实例构造函数");
        }

        static Person()
        {
            Console.WriteLine("静态构造函数");
        }
    }
复制代码

 为了更好演示,我们实例化对象两次代码如下:

     Person p = new Person();
     
Person p1
= new Person();

控制台运行结果如下:

从上述显示结果中至少可以看出:在调用构造函数之前就已经调用了静态构造函数。 那么我们比调用构造函数更早的时期是什么时候呢?啊,容我想想,直接声明该对象的变量(即直接第一次在加载该类下的所有成员时),不实例化就可以了。于是乎我们直接在控制台中声明变量即可,如下:

 Person p2;

运行,结果是什么都没有如下:

说明此时未调用静态构造函数, 那就是在此之后,现在是调用实例构造函数之前即对象不能实例化,也就是说访问实例成员指定也是不行了,那么要是如果访问静态成员,看行不行,我们在Person类中添加 

public static int age;

现在我们在控制台来访问该静态成员 Person.age = 1; 结果运行如下:

说明静态构造函数: 在类的成员第一次被访问之前,就会调用静态构造函数 。 如果还是不能理解我们直接这样做,在Person类中定义一个已经赋值的字段。如下

  public int temp = 0;

此时我们在控制台中实例化对象 Person p = new Person(); ,再运行下看看结果会怎样呢?一步步调试:

第一步:显然没有调用

第二步执行到赋值的字段时:

同样也证明了上面的结果。

补充

如果对静态成员不太理解下面就静态成员定义以及静态成员和实例成员区别做一点概括吧。

 静态成员

静态成员在类第一次加载时被创建。

静态成员只会被创建一次,所以有且仅有一份。

静态成员创建在静态存储区中,所以一旦被创建直到程序退出才会被回收。

静态成员与实例成员区别

生命周期:静态成员是从类第一次被加载时到程序完全退出时,但是实例成员则是在对象被创建时到该对象成为垃圾被垃圾回收器回收时。

存储位置:静态成员存储在静态存储区中,实例成员存储在堆空间相应的对象中。

《大话西游》你真的看懂了吗?

前天晚上去看了《大话西游之大圣娶亲》,虽然是一部重映电影,片方又新加了11分钟新的剧情,但是每次看这部经典之作都有不同的感想。 来看一部20年经久不衰的电影《大话西游》,1994年我们看它曾经捧...
  • CC1991_
  • CC1991_
  • 2017年04月24日 16:19
  • 1150

关于Git,你真的学会了吗?

“锋哥,Git有什么可说的,不就是git add添加,git commit提交嘛” 听说我要写一篇Git教程,小明不屑一顾地说。 “…”。 小明是我的一个学生。目前,是一名Android开发工程...
  • apple337008
  • apple337008
  • 2018年02月01日 22:41
  • 52

敏捷开发,你真的做对了吗?阿里文娱广告团队敏捷实践总结

阿里妹导读:很多人对敏捷开发有个普遍的误解,认为敏捷就是快,经常在需求没定义清楚的情况下就急于开工。事实上,这样做往往得不偿失。今天,我们邀请阿里巴巴敏捷教练问菊,为我们带来阿里文娱广告团队敏捷实践,...
  • zz901214
  • zz901214
  • 2018年02月02日 15:40
  • 111

构造函数,你真的弄懂了吗?

前言 看过我之前复习的随笔知道都是基础之上的语法,但是当我脑海开启回忆基础知识时,尤其是构造函数中先后执行顺序以及原因却是模棱两可,于是开始边编写边操笔来记叙下来。如果你正在学习基础语法或者是复...
  • quryktcs
  • quryktcs
  • 2017年05月04日 22:39
  • 48

你真的真的懂了吗?

背景:求(M~N中)K个不重复的随机整数        今天米老师在会议上出了这么一道题,这是老师在给大一的学生上课的时候出的题目。这看似很简单的题目,但是老师叫我们做的时候,大家居然都做不出来。...
  • huo_yun
  • huo_yun
  • 2013年06月04日 19:03
  • 1721

你真的爱了吗??

         你真的爱了吗? 有位心理学家曾写道,一个成熟称得上真爱的恋情必须经过四个阶段,那就是:   共存(codependent)   反依赖(counterdependent)   独立(...
  • DJBOY850317
  • DJBOY850317
  • 2008年05月09日 22:54
  • 564

你真的长大了吗?

你真的长大了吗? 在网上遇到一个昔日的好朋友,前段时间,她曾向我借钱,因为买房子,还差几万块。她是个很能干的女孩子,老公在读博士,没有多少收入,全靠她自己的积蓄。然而,我也很穷,所以没能借给她。 今天...
  • absurd
  • absurd
  • 2006年04月10日 21:55
  • 3005

你真的会php吗?

今天来讨论一道php代码审计的题,这是一道实验吧的题,链接: http://ctf5.shiyanbar.com/web/PHP/index.php 。 首先我们点开链接,并且查看源代码, 发...
  • JBlock
  • JBlock
  • 2017年12月07日 20:31
  • 755

三分钟电话~!你看懂了吗????

母爱无限
  • zhu198971
  • zhu198971
  • 2010年06月08日 15:25
  • 101

CSDN日报20170218——《你真的看懂无领导小组面试了吗?》

【剑指Offer】 你真的看懂无领导小组面试了吗? 作者:孙华强 在讨论中每个人的角色很公平,无核心人物、地位上的去中心化使得参与者在讨论时可以不受约束,充分展示自己。讨论围绕着一个实际问...
  • blogdevteam
  • blogdevteam
  • 2017年02月18日 20:37
  • 19607
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:构造函数你真的看懂了吗
举报原因:
原因补充:

(最多只允许输入30个字)