参考原文:https://blog.csdn.net/Osean_li/article/details/69624199
https://www.cnblogs.com/YuanSong/p/4351401.html
存在继承关系时,往往在实例化过程中,对各个类方法的执行比较混乱,查询验证之后才有了清晰的认识。
首先进行细分
1.类的成员分为:字段,属性,方法,构造函数
2.成员修饰符:静态成员,实例成员
不考虑继承的关系(没有继承,在单个类中)执行顺序为
1.静态字段
2.静态构造方法
3.实例字段
4.实例构造方法
其中 属性和方法只有在调用的时候才执行。即实例化过程中,没有调用属性和方法的语句时,不会执行属性和方法。
对象的创建过程是按照顺序完成了对整个父类及其本身字段的内存创建,并且字段的存储顺序是由上到下排列,最高层类的字段排在最前面。其原因是如果父类和之类出现了同名字段,则子类对象创建时,编译器会自动认为这是两个不同的字段而加以区别。
结果就是:在继承关系中,子类实例化时,先依次执行子类的静态字段、静态方法和实列字段;然后依次执行父类的成员(静态字段、静态方法、实例字段和实例构造方法);最后执行子类的实例构造方法。更多重继承时以此类推。
注:上述结果是一般情况,若存在重写等特殊情况则输出结果会不同
public class Animal { static string baseClassName; protected string _skincolor; Instancevariable iv = new Instancevariable("父类实例成员变量"); static Instancevariable siv = new Instancevariable("父类静态成员变量"); static Animal() { baseClassName = "父类静态构造函数"; Console.WriteLine(baseClassName); } public Animal() { _skincolor = "父类构造函数"; Console.WriteLine(_skincolor); } } public class Instancevariable { public Instancevariable(string cls) { Console.WriteLine(cls); } } public class Horse : Animal { static string horseClassName; Instancevariable iv = new Instancevariable("子类实例成员变量"); static Instancevariable siv = new Instancevariable("子类静态成员变量"); public Horse() : base() { _skincolor = "子类类构造函数"; Console.WriteLine(this._skincolor); } static Horse() { horseClassName = "子类静态构造函数"; Console.WriteLine(horseClassName); } } class Program { static void Main(string[] args) { Horse h = new Horse(); Console.ReadLine(); } }
补充说明
1.并不是每次实例化都是上面的顺序。因为静态的成员只是在第一次实例化的时候执行,以后再实例化都不会在执行。静态的成员意味着大家共享,且只有这一个。第一次实例化得到静态成员后,以后大家都共享,再次实例化,没有必要也不允许执行静态成员的部分。
2.在类中如果不添加访问修饰符,默认是静态的
3.非静态的字段,属性,方法,不能够作为右值。
4.构造引用类型的对象时,调用实例构造方法之前,为对象分配的内存总是先被归零,构造器没有显式重写字段,字段的值为0或者null,例如class Test 中的
public int mNum;mNum 默认为0
5.C#编译器提供了简化语法,允许在变量定义的时候就进行初始化(C++应该不行,在构 造函数汇总)但是存在了代码膨胀的问题。多个字段在定义时初始化,同时存在多个构造方法,每个构造方法都会把这些字段初始化的代码搬到自己的内部,这样造成代码的膨胀。
6.为了避免这样情况,可以把这些字段的初始化放到一个无参构造方法内,其他的构造方法显式调用无参构造方法。
7.初始化字段的两种方法
①使用简化语法:在定义的时候初始化
② 在构造方法内初始化。