先上一段代码:
父类:
package demo;
public class Insect {
private int i = 9;
protected int j;
Insect() {
System.out.println("i = " + i + ", j = " + j);
j = 39;
}
private int p=print(" Insect.p initialized");
private static int x1 =print("static Insect.x1 initialized");
public static int print(String s) {
System.out.println(s);
return 47;
}
public static void dd()
{
System.out.println("aa ");
}
}
子类:
package demo;
public class Beetle extends Insect {
private int k = print("Beetle.k initialized");
public Beetle() {
System.out.println("k = " + k);
System.out.println("j = " + j);
}
public static void dd()
{
System.out.println("dd ");
}
private static int x2 = print("static Beetle.x2 initialized");
public static void main(String[] args) {
System.out.println("Beetle constructor");
Beetle b = new Beetle();
}
}
输出结果:
static Insect.x1 initialized
static Beetle.x2 initialized
Beetle constructor
Insect.p initialized
i = 9, j = 0
Beetle.k initialized
k = 47
j = 39
分析过程:
当我们运行此程序的时候,主线程启动,编译器开始寻找Beetle.class这个类,找到后,开始加载这个类,加载的过程中发现有extends关键字,所以编译器开始去加载父类insect.class(如果在加载insect.class的过程中,发现它还有基类,则先加载它的基类,以此类推)。
此时(加载insect类时),insect的静态代码将被执行(静态成员的初始化),所以此时打印出:static Insect.x1 initialized;当insect的静态代码执行之后,Beetle的静态代码开始执行,所以打印出:static Beetle.x2 initialized。
到现在为止,所有基类和当前类的静态初始化动作已经执行完成了,可以初始化对象了
接下来,从main函数开始,执行第一句,打印出Beetle constructor;
下面执行Beetle b = new Beetle(),首先为Beetle分配内存空间,初始化以下三个动作:
(1) 对于 char,short,byte,int,long,float,double等基本数据类型的变量会初始化为0,boolean类型初始化为false
(2) 对于引用类型的变量,会初始化为null
(3) 如果没有显示的定义构造器,则编辑器会自动创建一个无参的构造器,反之,不会。
在Beetle内的代码执行之前,首先会调用基类的构造器,在基类的构造器内的代码执行之前,首先要对基类的非静态成员初始化。此时打印出:Insect.p initialized,当执行后,基类的构造函数里面的代码开始执行,所以打印出:i = 9, j = 0;此时j被初始化为39。
当基类的构造器代码执行之后,首先要对Beetle的非静态成员进行显示的初始化,此时K被初始化为47,并且打印出:Beetle.k initialized;等初始化完成后,Beetle构造器里的代码开始执行,所以打印出:K=47;J=39。现在,程序终于分析完了!
值得注意的是:静态成员初始化是从最顶层的类开始的,因为子类成员的初始化可能回用到基类的成员。
所以类加载以及初始化的顺序是:类的静态成员初始化分配内存(有父类的先父类,然后自己)->然后main方法执行->类初始化{类非静态成员的初始化,然后执行构造器(有父类的先给父类的非静态成员初始化,然后父类的构造器)}
易错的地方:当执行到子类的非静态成员初始化时,执行这一句:private int k = print("Beetle.k initialized")时,会调用到父类的print函数,将参数Beetle.k initialized传给 print(),并且返回47给k。注意:此时把值返回给调用它的地方,即k。