一、第一个例子:
class Insect
{
int i=9;
int j;
Insect()
{
prt("i="+i+",j="+j);
j=39;
}
static int x1=prt("static Insect.x1 initialized");
static int prt(String s)
{
System.out.println(s);
return 47;
}
}
public class Beetle extends Insect{
int k=prt("Beetle.k initialized");
Beetle()
{
prt("k="+k);
prt("j="+j);
}
static int x2=prt("static beetle.x2 initialized");
static int prt(String s)
{
System.out.println(s);
return 63;
}
public static void main(String[] args)
{
prt("Beetle Constructor");
Beetle b=new Beetle();
}
}
1.析一段java代码执行后的结果,我们得先找到程序的入口,也就是mian()方法,才能着手分析。
2.发现mian()方法在类Beetle中,那么首先要将Beetle类加载到内存中,但立即发现Beetle类继承与Insect类,于是要先将Insect类加载到内存中。
3.在将类加载到内存时,会发生static初始化(static就是在类被第一次加载的时候执行,以后就不在执行)。那么此时先初始化Insect 的静态变量x1。
4.接下来,加载Beetle类到内存中,并执行Beetle类的static初始化,即x2。
5.类被加载完成之后。转入main()方法当中顺序执行main()方法体内的代码。
6.实例化Beetle的一个类时,执行Beetle类的构造方法,那么首先要执行其基类Insect的构造方法。
7.在执行Insect的构造方法之前,按顺序初始化Insect的非static变量。
8. 接着执行Insect的构造方法。
9.执行子类Beetle 的构造方法之前同理先按顺序初始化Beetle 的非static变量。
10.接着执行Beetle 的构造方法。完成对Beetle类的实例化过程,即执行Beetle b=new Beetle();
所以以上代码输出结果为:
static Insect.x1 initialized
static beetle.x2 initialized
Beetle Constructor
i=9,j=0
Beetle.k initialized
k=63
j=39
通过以上总结:
在有类继承时,会从父类到子类依次执行static初始化。主类中的static初始化会在main()方法之前执行。所以初始化顺序:
先初始化父类的静态代码-->初始化子类的静态代码-->
(创建实例时,如果不创建实例,则后面的不用的执行)初始化父类非静态代码-->初始化父类构造函数-->
初始化子类非静态代码-->初始化子类构造函数
二、再看一个例子:
package extend;
public class X {
Y y=new Y();
static{
System.out.println("tttt");
}
X(){
System.out.println("X");
}
public static void main(String[] args) {
new Z();
}
}
class Y{
Y(){
System.out.println("Y");
}
}
class Z extends X{
Y y=new Y();
static{
System.out.println("tt");
}
Z(){
System.out.println("Z");
}
}
执行顺序:
1、由于main()方法在类X中,从main()方法入口执行程序时,首先将类X加载到内存中,加载的时候执行类X 的static初始化。
2、加载完毕,执行main()方法中的语句,实例化一个Z 的对象。
3、由于要实例化Z 的对象,所以要将Z类加载到内存中,由于类Z继承与类X,所以先要加载类X,但是发现类X已被加载。
4、加载类Z时,执行类Z 的static初始化。
5、类Z加载完毕。准备执行类Z 的构造方法。
6、先转去执行其父类X 的构造方法。
7、在执行类X 的构造方法之前先初始化X 的非静态变量(包括句柄),按顺序执行。
8、执行类X 的构造方法
9、按顺序初始化类 Z 的非静态变量。
10、初始化类Z 的构造方法,至此,类Z 的实例对象创建完毕,程序执行结束。
所以,执行结果为:
tttt
tt
Y
X
Y
Z