Java的初始化顺序

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");
	}

}

上面一个类分四个部分,普通成员、构造器、静态域、静态成员,然后执行 new TestInitial(),好了,看输出:

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,初始化肯定是在static之后,用 new TestInitial()试试:

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里提到了一种特殊的情况,是在子类的构造方法里进行多态的函数调用。

因为多态顾名思义是动态绑定、加载时绑定,所以其实并不影响初始化的顺序。


你可能感兴趣的:(Java,java,类,对象)