首先进行细分
1.类的成员分为:字段,属性,方法,构造函数
2.成员修饰符:静态成员,实例成员
不考虑继承的关系执行顺序为
1.静态字段
2.静态构造方法
3.实例字段
4.实例构造方法
其中 属性和方法只有在调用的时候才执行。
下面是一段代码例子
定义了一个类,当我们实例化的时候
Test test = new Test();
通过VS2008仿真 执行过程是
0. 静态的最先执行,仿真编译略过
1. F11 执行 public int mNum2=2; //简单的初始化字段
2. private int mNum3 = 3;
private int mNum4 = 4;
3. public Test() { temp = 1;mNum = 0; } //构造函数
以上是执行的顺序:
与上面描述的的执行过程稳和,属性和字段跳过。public int mNum;也执行了,只不过系统默认赋值为空(null)或者0,系统西东除了的仿真时候跳过。
class Test
{
public static int temp;
public int mNum;
public int mNum2=2;
public void look()
{
Console.WriteLine("看我,我是test");
Console.WriteLine("mNum={0}", mNum);
}
private int mNum3 = 3;
private int mNum4 = 4;
public int Num3
{
get { return mNum3; }
set { mNum3= value; }
}
public Test()
{
temp = 1;
mNum = 0;
}
}
当存在继承关系的时候,执行的顺序。
1. 子类的静态字段
2. 子类的静态构造方法
3. 子类的实例字段
4. 父类的静态字段
5. 父类的静态构造方法
6. 父类的实例字段
7. 父类的实例构造方法
8. 子类的实例构造方法
下面是例子
1. 首先执行 class A中 int x = 1;,执行所有已经初始化后的字段,当执行到构造函数首执行父类字段
2. int sd = 6;
3. public A(),首先会去执行父类。
4. 0. 静态的最先执行,仿真编译略过
1. F11 执行 public int mNum2=2; //简单的初始化字段
2. private int mNum3 = 3;
private int mNum4 = 4;
3. public Test() { temp = 1;mNum = 0; } //构造函数
5. public A()
{
PrintFields();
look();
}// 执行子类中自己的构造函数
6. public virtual void PrintFields() ;执行自己类中有意义的虚函数
7. 执行调用父类的函数 look();
8. 接下来就将要执行 class B 中的内容了。过程类似,先一步一步的执行A类,在执行Test类,实现继承。
9. 忽略部分细节,降调B类中的细节。
int z=2;
public B() 运行到这里的时候,再次执行到
public A()
{
PrintFields();
look();
}
的构造函数的时候,由于执行的是实例化B类,又在B类中重写了PrintFields();,实现多态。所以执行 public override void PrintFields()
{
Console.WriteLine("x={0},y={1}", "b", z);
}
所以此时的 z=2;
而不是 public B()
{
z = -1;
}
中的z=-1,因为还没有执行到它,随后才执行子类中的构造函数。
10. 接下来是执行C类的实例化,C类中没有写C的构造函数,但是还是执行到了
B类(它的父类)中int z=2;,是因为,默认给写了无参的C类构造函数。
相当与 public C(){}
11. 所以任然能够继承,执行 public override void PrintFields()
{
Console.WriteLine(“j={0},k={1}”, “CC”, y);
}
class A :Test
{
int x = 1;
public A()
{
PrintFields();
look();
}
int c;
int sd = 6;
public virtual void PrintFields()
{
Console.WriteLine("j={0},k={1}", "AA", "AA");
}
}
class B : A
{
int y;
int z=2;
public B()
{
z = -1;
}
public override void PrintFields()
{
Console.WriteLine("x={0},y={1}", "b", z);
}
}
class C : B
{
int x = 1;
int y = 3;
public override void PrintFields()
{
Console.WriteLine("j={0},k={1}", "CC", y);
}
}
static void Main(string[] args)
{
Test test = new Test();
A a = new A();
B b = new B();
C c = new C();
Console.ReadKey();
}
补充说明
- 并不是每次实例化都是上面的顺序。因为静态的成员只是在第一次实例化的时候执行,以后再实例化都不会在执行。静态的成员意味着大家共享,且只有这一个。第一次实例化得到静态成员后,以后大家都共享,再次实例化,没有必要也不允许执行静态成员的部分。
- 在类中如果不添加访问修饰符,默认是静态的
- 非静态的字段,属性,方法,不能够作为右值。
- 构造引用类型的对象时,调用实例构造方法之前,为对象分配的内存总是先被归零,构造器没有显式重写字段,字段的值为0或者null,例如class Test 中的
public int mNum;mNum 默认为0 - C#编译器提供了简化语法,允许在变量定义的时候就进行初始化(C++应该不行,在构 造函数汇总)但是存在了代码膨胀的问题。多个字段在定义时初始化,同时存在多个构造方法,每个构造方法都会把这些字段初始化的代码搬到自己的内部,这样造成代码的膨胀。
- 为了避免这样情况,可以把这些字段的初始化放到一个无参构造方法内,其他的构造方法显式调用无参构造方法。
- 初始化字段的两种方法
①使用简化语法:在定义的时候初始化
② 在构造方法内初始化。
效果图