java类的初始化顺序

下面的程序说明子父类中成员变量的构造顺序


abstract class SupConstruction
… {

SupConstruction()
… {

System.out.println( “ SupConstruction constructed! “ );

con();

System.out.println( “ con “ );
}

abstract void con(); // 虚拟函数
}


public class Construction extends SupConstruction // 继承虚拟类
… {

int i = 9 ;

Construction()
… {

super (); // 调用构造函数

System.out.println( “ Construction constructed “ + i);
}


public void con() // 超越虚拟方法
… {

System.out.println( “ Con “ + i);
}

public static void main(String [] args)
… {

Construction c = new Construction(); // 实例化.
}
}

输出结果:

SupConstruction constructed!
Con 0
con
Construction constructed 9

其中的Con 0说明在此时i已经被声明,并且被赋上初值(或者说该变量所占的内存空间被清空)。同时也说明i=9,还没有被执行。上面程序的顺序是这样的:当new
一个Construction的时候,调用Construction的构造函数。然后进入父类的构造函数。而在进入Construction的构造函数之前 或许
int i已经被执行(这点以后还会说明为什么),但i=9没有被执行。进入父类的构造函数函数后打印SupConstruction
constructed!,然后调用自己的虚方法。因为多态的机制,函数将调用子类的同名方法。在那里打印Con
0。然后返回到父类打印con,再返回子类的构造函数打印Construction constructed 9。结束构造。

下面讲讲为什么说进入Construction的构造函数之前或许int i已经被执行。看下面的例子:


class Test
… {

int t1 = 3 ;

static int t2 = 4 ;

static
… {

System.out.println( “ Static block “ + “ t2: “ + t2);
}


public Test()
… {

System.out.println( “ Construct:t1: “ + t1 + “ t2: “ + t2);

t1 = 30 ;

t2 = 40 ;
}
… {


t2 = 9 ;

System.out.println( “ nonstatic,t1: “ + t1 + “ t2: “ + t2);

}

public static void TestClass()
… {

System.out.println( “ Static Method: “ + “ t2: “ + t2);
}

}


public class Life
… {

public static void main(String [] args)
… {

Test.TestClass();

Test t = new Test();

}

}

打印结果:

Static block t2:4
Static Method:t2:4
nonstatic,t1:3t2:9
Construct:t1:3t2:9

这说明在执行构造函数之前nonstatic块就已经被执行。而且看出了初始化顺序static变量->static块->非static变量->非static块-

构造函数。但是不是真的是这样?看下面的例子:


class SupTest
… {

int st1 = 12 ;

static int st2 = 19 ;

public SupTest( int x)
… {

st1 = x;
}
}


class Test extends SupTest
… {

int t1 = 3 ;

static int t2 = 4 ;

static
… {

System.out.println( “ super static : “ + “ t2: “ + SupTest.st2);


System.out.println( “ Static block “ + “ t2: “ + t2);
}


public Test()
… {

super (t1);

System.out.println( “ Construct:t1: “ + t1 + “ t2: “ + t2);

t1 = 30 ;

t2 = 40 ;
}
… {

t2 = 9 ;

System.out.println( “ nonstatic,t1: “ + t1 + “ t2: “ + t2);

}

public static void TestClass()
… {

System.out.println( “ Static Method: “ + “ t2: “ + t2);
}

}


public class Life
… {

public static void main(String [] args)
… {

Test.TestClass();

Test t = new Test();

}

}

打印结果:

Life.java:24: 无法在调用父类型构造函数之前引用 t1
super(t1);
^
1 错误

可惜编译的时候就报错。然后将 super(t1);改为 super(t2)编译运行成功。

这说明在调用父类构造函数前,子类的t1并没有声明并被缺省初始化。然后对于第一个程序在子类Construction 中添加非静态块打印i;得到打印结果:

SupConstruction constructed!
Con 0
con
9
Construction constructed 9

这就道出了真正的构造顺序:(结合static只属于类的经验)

加载class路径->static变量初始化->static块->进入子类构造函数->进入父类构造函数->父类虚方法下传->子类非static变量声明并清空
相应的内存空间->多态机制,子类同名函数调用->父类构造函数退出->子类非static变量赋值->子类非static块调用->子类构造函数退出->对象构造完
成。

  • 本文作者: 帐前卒
  • 本文链接: http://chillyc.info/2007/1647606/
  • 版权声明: 本博客所有文章除特别声明外,只能复制超链接地址,且必须注明出处!