thinking in Java里是这么说的:类在任何static成员被访问时被加载,包括了普通的static变量、域以及构造方法,构造方法是一个特殊的隐式的静态方法。
第一次加载类时,步骤如下:
1、查找类路径,加载class文件,如果此类有父类,则加载其父类,递归下来,根基类会被加载
2、在从根基类开始加载的过程中,进行静态初始化,只在首次加载时进行一次,因为子类的static初始化可能会依赖其基类,所以要自顶向下。
3、如需创建对象,则在堆上计算并为此对象分配足够的空间;如不需创建对象,则到这一步就为止了。
4、存储空间清零,对新对象里的所有数据和域设置默认值或者null值。(我觉得这里的所有,是包括了所有的基类和子类,参见Thinking in Java里的构造方法里的多态方法行为)
接下来这两步依然是一个从根基类开始,自顶向下的整体递归 {
5、执行所有出现于字段定义处的初始化动作。
6、构造器。
}
用一段代码测试一下。
public class TestUtil {
public TestUtil(String tu) {
System.out.println(tu);
}
}
public class TestInitial {
static TestUtil sTu = new TestUtil("static member");
static {
System.out.println("static field");
}
TestUtil mTu = new TestUtil("custom member");
public TestInitial() {
System.out.println("constructor");
}
}
static member
static field
custom member
constructor
顺序就是:静态成员、静态域、普通成员、构造器。
但是如果不生成对象呢,比如只访问静态变量或者域,如TestUtil tu = TestInitial.sTu;,再看输出:
static member
static field
那继续改一下,在TestInitial类里加一个静态方法如下:
public static void sTest() {
System.out.println("staic method");
}
static member
static field
staic method
好了,我觉得可以这样理解,类的静态域和静态成员是同一个区,当static区有一任意一个被初始化时,其他都会一起初始化,并且顺序为:静态成员、静态域。
好吧,继续加! 再加一个非静态域,如下:
{
System.out.println("custom field");
}
static member
static field
custom field
custom member
constructor
可以看到非静态域的初始化是在普通成员的前面,好了,不过还没完。
如果有父类呢,再继续看看,代码太简单了我就不贴了,创建一个子类对象,初始化顺序如下:
parent static member
parent static field
static member
static field
parent custom field
parent custom member
parent constructor
custom field
custom member
constructor
如果不创建子类对象,只使用子类的静态变量或静态方法:
parent static member
parent static field
static member
static field
好了,可以看到,如果有父类的情况下
1、首先自顶向下初始化static域
2、然后是最顶层的父类的普通成员以及非static域、构造方法,一直向下到最底层。
在Thinking in Java里提到了一种特殊的情况,是在子类的构造方法里进行多态的函数调用。
因为多态顾名思义是动态绑定、加载时绑定,所以其实并不影响初始化的顺序。