综合网上的相关帖子和我自己的调试,研究了一下关于JAVA继承类的静态变量、成员变量、父子类构造方法调用顺序问题。首先看一段程序:
class X {
Y b = new Y();//7、这里是父类成员变量初始化
static Y sb= new Y();//1、父类静态变量,输出static Y(静态代码块先初始化),2、Y
static{
System.out.println("static X父类静态代码块");//3、执行静态代码块
new Y();//4、这里只是输出Y,有static Y(静态代码块只执行一次)
}
X() {
System.out.println("X");//8、父类成员变量初始化之后,执行父类构造器输出X
}
}
class Y {
static{
System.out.println("static Y");
}
Y() {//执行构造函数
//这里有个super()==Object()
System.out.println("Y");
}
}
public class Z extends X {
final static int mead=45;
final byte b=16;
static Y sb= new Y();//5、子类的静态变量,输出Y
static{
System.out.println("static Z");//6、子类的静态代码块
}
Y y = new Y();//9、这里是子类成员变量初始化
Z() {
//这里有super()==new X()
this.y = null;
System.out.println("Z");//10、子类成员变量初始化之后,执行子类构造器输出Z
}
public static void main(String[] args) {
new Z();
}
}
执行结果:
static Y
Y
static X父类静态代码块
Y
Y
static Z
Y
X
Y
Z
解释:
static的东西在编译的时候就向内存要到了存取空间,他们的初始化要早于非static,顺序是先父类再子类。
初始化类,先执行super()父类的的构造函数(final和static之后),父类的构造函数先执行super()直到object super(),完了执行一般成员变量的初始化
一般成员变量初始化完毕,执行构造器里面的代码(super()之后的代码).
父类的初始化完成后(子类构造器里面super执行完毕),才轮到子类的成员变量初始化
子类成员变量初始化完毕,开始执行子类构造器里面的代码(super()之后的代码).
注意:
静态块和静态变量的调用顺序是按照书写顺序执行的,比如上边X类中静态块和静态变量的书写顺序颠倒如下:
class X {
Y b = new Y();
static{
System.out.println("static X父类静态代码块");
new Y();
}
static Y sb= new Y();
X() {
System.out.println("X");
}
}
则执行结果为:
static X父类静态代码块
static Y
Y
Y
Y
static Z
Y
X
Y
Z
最后:
确定变量空间和初始化赋值是分开进行的,先一次性确定静态成员变量空间 并赋给二进制0 ,然后按照书写顺序逐一赋值
如下代码,输出结果是0.0
public class Test {
static int i=f();
static double d=0.1234;
public static void main(String[] args) {
new Test();
}
static int f(){
System.out.println(d);
return 3;
}
}
静态成员初始化在静态构造函数之前,静态构造函数调用在静态方法前,而静态成员初始化又是在什么时候调用的呢?
类被首次提到(实例化或调用静态对象/方法)时开始执行类的静态成员初始化,初始化后如果存在静态构造函数则调用静态构造函数,之后进行相应操作。静态成员不会因为先调用而先初始化。
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/pisota/archive/2010/02/27/5332848.aspx