构造函数 青旅半醒 2022-06-17 10:38 212阅读 0赞 # 前言 # 看过我之前复习的随笔知道都是基础之上的语法,但是当我脑海开启回忆基础知识时,尤其是构造函数中先后执行顺序以及原因却是模棱两可,于是开始边编写边操笔来记叙下来。如果你正在学习基础语法或者是复习基础语法的路上,这篇文章或许对你亦有帮助(当然msdn也有相关定义,但是个人觉得要是看完定义后再去摸索下,或许会理解的更透彻吧)。【特此注意:高手请绕过道而走!】 # 继承之构造函数 # 首先我们定义一个Person类,并给个构造函数。代码如下: ![复制代码][copycode.gif] public class Person { public string Name { get; set; } public int Age { get; set; } public bool Gender { get; set; } public Person() { Console.WriteLine("父类构造函数"); } } ![复制代码][copycode.gif] 再写个Bob类继承该父类,同时给个构造函数,其代码如下: ![复制代码][copycode.gif] public class Bob : Person { public Bob() { Console.WriteLine("子类构造函数"); } } ![复制代码][copycode.gif] 接下来就在控制台实例化Bob类 Bob b = new Bob(); 看调用构造函数先后执行顺序。结果输出如下: ![141531270205298.png][] 从这输出来看你会不会妄下结论说先调用的父类构造函数再调用子类的构造函数呢?如果你这样说的话,也就是说当我们实例化对象子类时,但是它去执行了父类的构造函数,好像有点神奇。好吧,我们接下来继续看,我们再定义一个Student类继承该Bob类。代码如下: ![复制代码][copycode.gif] public class Student : Bob { public Student() { Console.WriteLine("学生类构造函数"); } } ![复制代码][copycode.gif] 然后在控制台实例化Student类 Student s = new Student(); ,结果打印出: ![141541123798533.png][] 依然是调用的父类构造函数,所以现在就下结论:子类继承父类,实例化子类对象,首先调用的是父类构造函数。好,结论似乎言之过早,我们来断点调试下不就可以得出答案所在了吗。 看下面图片,一步步断点截图: 第一步:不用说 ![141545369268979.png][] 第二步:调用子类构造函数即Bob类 ![141551537707585.png][] 第三步:调用父类构造函数即Person类 ![141548491459622.png][] 第四步:执行父类的构造函数 ![141549505208306.png][] 最后一步:执行子类构造函数 ![141550368641815.png][] 所以总结如下:子类继承父类时构造函数执行的先后顺序: 1. 调用子类构造函数 2. 调用父类构造函数 3. 执行父类构造函数 4. 执行子类构造函数 但是此时问题来了,为什么我们实例化子类对象时,最后去调用了父类的构造函数?其实是有道理可循的,我忘记了base关键字的存在,当你在子类编写构造函数时,如果没有显式的调用基类的构造函数,那么会默认在其后面添加 一个 :base() 以此来调用基类的无参构造函数。所以上述问题就解决了。 msdn上所说base关键字概念有两点: * 调用基类上已被其他方法重写的方法。 * 指定创建派生类实例时应调用的基类构造函数。 接下来如果我们在父类中将无参构造函数修改为有参构造函数会怎样呢,这是我们再生成出现如下错误: ![141608203322953.png][] 因为上面已经说的很清楚了,如果父类没有无参构造函数,但是子类默认会带调用父类无参的构造函数所以会出错。所以解决办法 就是在子类中构造函数显示的用 :base 来调用父类有参构造函数即可,具体不再演示。 但是问题又来了:为什么要让父类构造函数优先于子类构造函数执行呢??????请看下面给出合理解释。 我们将整个代码进行整合如下来讨论下: ![复制代码][copycode.gif] 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(); } } ![复制代码][copycode.gif] 我们只需看上述代码中标记为红色的(1)和(2),如果我们现在实例化Bob类并传参 age = 12 ,此时我们当然希望的是Bob类中age = 12,如果此时先执行子类那完了,因为有 :base(name,11) ,所以此时的 age = 11 ,这样不就造成了意想不到的结果了吗,明明传的12,结果为11,结果数据产生严重的冲突,也就是数据的不一致。如果先执行父类构造函数,此时子类age为11,但是当执行到子类构造函数时,因为我传的是12所以其age就为12。这才是我们需要的结果。 # 静态构造函数 # 我们继续就上述例子中的Person类为例进行分析,代码如下: ![复制代码][copycode.gif] 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("静态构造函数"); } } ![复制代码][copycode.gif] 为了更好演示,我们实例化对象两次代码如下: Person p = new Person(); Person p1 = new Person(); 控制台运行结果如下: ![141654283017921.png][] 从上述显示结果中至少可以看出:在调用构造函数之前就已经调用了静态构造函数。 那么我们比调用构造函数更早的时期是什么时候呢?啊,容我想想,直接声明该对象的变量(即直接第一次在加载该类下的所有成员时),不实例化就可以了。于是乎我们直接在控制台中声明变量即可,如下: Person p2; 运行,结果是什么都没有如下: ![141659531767237.png][] 说明此时未调用静态构造函数, 那就是在此之后,现在是调用实例构造函数之前即对象不能实例化,也就是说访问实例成员指定也是不行了,那么要是如果访问静态成员,看行不行,我们在Person类中添加 public static int age; 现在我们在控制台来访问该静态成员 Person.age = 1; 结果运行如下: ![141712049264750.png][] 说明静态构造函数: 在类的成员第一次被访问之前,就会调用静态构造函数 。 如果还是不能理解我们直接这样做,在Person类中定义一个已经赋值的字段。如下 public int temp = 0; 此时我们在控制台中实例化对象 Person p = new Person(); ,再运行下看看结果会怎样呢?一步步调试: 第一步:显然没有调用 ![141728232547565.png][] 第二步执行到赋值的字段时: ![141729307544943.png][] 同样也证明了上面的结果。 # 补充 # 如果对静态成员不太理解下面就静态成员定义以及静态成员和实例成员区别做一点概括吧。 ## 静态成员 ## 静态成员在类第一次加载时被创建。 静态成员只会被创建一次,所以有且仅有一份。 静态成员创建在静态存储区中,所以一旦被创建直到程序退出才会被回收。 ## 静态成员与实例成员区别 ## 生命周期:静态成员是从类第一次被加载时到程序完全退出时,但是实例成员则是在对象被创建时到该对象成为垃圾被垃圾回收器回收时。 存储位置:静态成员存储在静态存储区中,实例成员存储在堆空间相应的对象中。 [copycode.gif]: /images/20220617/cd5cba8405c14d8ab5c4a17bcdb6077e.png [141531270205298.png]: /images/20220617/ac87bc76e4c44de69e1a6ad9f2bf0c10.png [141541123798533.png]: /images/20220617/4ed66a413ff04b2591708e899e15a5ae.png [141545369268979.png]: /images/20220617/b7f1659671594a3d8db3b651393cabed.png [141551537707585.png]: /images/20220617/a201be5a5dd0404d80a68b747fbfbc28.png [141548491459622.png]: /images/20220617/1e51530faa0a4be6bde1aafad526ff08.png [141549505208306.png]: /images/20220617/92636761c09045bfa9ceae9d388b8254.png [141550368641815.png]: /images/20220617/d3afef695a054eab88063a4d484e1243.png [141608203322953.png]: /images/20220617/334776009edb43be9f9ff7c2d9f0ee17.png [141654283017921.png]: /images/20220617/cad06182d9ac4bebbc364f68c1742f41.png [141659531767237.png]: /images/20220617/c910eb3451e64da8809e3ead1eb5f5ef.png [141712049264750.png]: /images/20220617/1997e77dbadc46ff8cd5ee877d80a04c.png [141728232547565.png]: /images/20220617/e9d7ce1107694158a11137afc3cfbe8e.png [141729307544943.png]: /images/20220617/e93720a2907b491ca05cc01d62b5942f.png
相关 构造函数 PHP中对类进行实例化的同时会调用类的构造函数进行一些初始操作,如为类中的成员变量赋初值,可以说构造函数是类的入口。 创建构造函数 在PHP4.x中构造函数是与 绝地灬酷狼/ 2022年07月30日 13:52/ 0 赞/ 148 阅读
相关 构造函数 前言 看过我之前复习的随笔知道都是基础之上的语法,但是当我脑海开启回忆基础知识时,尤其是构造函数中先后执行顺序以及原因却是模棱两可,于是开始边编写边操笔来记叙下来。如果你 青旅半醒/ 2022年06月17日 10:38/ 0 赞/ 213 阅读
相关 构造函数 构造函数和析构函数是两个非常特殊的函数:它们没有返回值。这与返回值为void的函数显然不同,后者虽然也不返回任何值,但还可以让它做点别的事情,而构造函数和析构函数则不允许。 客官°小女子只卖身不卖艺/ 2022年06月09日 06:21/ 0 赞/ 177 阅读
相关 构造函数 class Person { private String name; private int age; / 阳光穿透心脏的1/2处/ 2022年06月08日 00:44/ 0 赞/ 193 阅读
相关 构造函数 java之构造函数 一、构造函数的作用主要是在类的对象创建时定义初始化的状态,而一个类可以有多个构造函数,以重载的形式存在。不能使用构造器名称来调用另一个构造器,而是应该 刺骨的言语ヽ痛彻心扉/ 2022年06月02日 10:21/ 0 赞/ 211 阅读
相关 构造函数 构造函数特点: 函数名与类名相同、不用定义返回值类型、没有return语句、构造函数可以有多个并以重载的方式存在 构造函数的作用: 给new出来的对象进行初始化 末蓝、/ 2022年06月01日 09:23/ 0 赞/ 198 阅读
相关 构造函数 这里假设类名为Complex 无参数构造函数 系统自动生成默认的无参构造函数,函数为空 Complex(void) { m_re 灰太狼/ 2022年05月09日 04:28/ 0 赞/ 231 阅读
相关 构造函数 1、什么是构造函数? > 构造函数是一种特殊的函数,主要用来创建对象的初始化对象,即为对象成员变量赋初始值,总与new运算符一起使用在创建对象的语句中,特别的是一个类可以 港控/mmm°/ 2022年05月05日 09:46/ 0 赞/ 201 阅读
相关 构造函数 -------------------- 先来说构造函数吧,在谈构造函数之前还是根据自己之前对面向对象的“类与对象”的概念引入之后的再来讨论这个问题,之前我们说过世间的 绝地灬酷狼/ 2022年02月03日 11:04/ 0 赞/ 237 阅读
相关 构造函数 什么时候定义构造函数? > 当分析事物时,该事物存在具备一些特性或行为,那么将这些内容定义在构造函数中。 构造函数特点: 函数名与类名相同 不用定义返回值类型 旧城等待,/ 2021年09月14日 08:54/ 0 赞/ 329 阅读
还没有评论,来说两句吧...