类的初始化
package reusing.ex5;
import static net.mindview.util.Print.*;
public class Father {
static {
print("父类静态代码块");
}
{
print("父类构造代码块");
}
static int i = a();
static int a() {
print("父类静态域");
return 1;
}
int j = b();
int b() {
print("父类普通域");
return 1;
}
Father() {
print("父类构造方法");
}
}
package reusing.ex5;
import static net.mindview.util.Print.*;
public class Son extends Father {
static int i = c();
static int c() {
print("子类静态域");
return 1;
}
static {
print("子类静态代码块");
}
Son() {
print("子类构造方法");
}
int j = d();
int d() {
print("子类普通域");
return 1;
}
{
print("子类构造代码块");
}
}
package reusing.ex5;
public class ClassInitialization {
public static void main(String[] args) {
new Son();
}
}
package reusing.ex5;
public class ClassInitialization2 {
public static void main(String[] args) {
new Son();
new Son();
}
}
父类代码的书写顺序:
父类静态代码块
父类构造代码块
父类静态域
父类普通域
父类构造方法
子类代码的书写顺序:
子类静态域
子类静态代码块
子类构造方法
子类普通域
子类构造代码块
从执行结果的输出顺序与父类,子类的代码书写顺序对比,结合《java编程思想》一书分析如下。
在创建的子类的第一个对象的时候,加载器开始加载子类的.class文件,在对它进行加载的过程中,编译器注意到它有一个父类(这是由关键字extends得知的),如果该父类还有其自身的父类,那么第二个父类就会被加载,如此类推。
加载完成后,初始化过程如下,
首先从父类到子类依次初始化 静态代码块和静态域(两者的初始化顺序与书写顺序相同),然后从父类到子类依次初始化 构造代码块和普通域(两者的初始化顺序与书写顺序相同)还有构造方法(总是最后被初始化)。
注意:静态代码块和静态域只会在第一次创建对象时被初始化,后面再次创建对象不会被初始化。每次创建子类对象,父类总是会被优先初始化(包括普通域,构造代码块,构造方法)