Java 深入解析种的初始化顺序

Java 深入解析类的初始化顺序

下面用阿里2013校招笔试最后的选做题作为例子:

首先,输出是:

1:i    i=0    n=0
2:j    i=1    n=1
3:构造块    i=2    n=2
4:构造函数 t1    i=3    n=3
5:Second    i=4    n=4
6:j    i=5    n=5
7:构造块    i=6    n=6
8:构造函数 Second_Builder    i=7    n=7
9:s_j    i=8    n=8
10:Second 构造体    i=9    n=9
11:静态块1    i=10    n=10
12:j    i=11    n=11
13:构造块    i=12    n=12
14:构造函数 t2    i=13    n=13
15:静态块2    i=14    n=99
16:静态块3    i=15    n=100
17:j    i=16    n=101
18:构造块    i=17    n=102
19:构造函数 init    i=18    n=103


函数以及解析如下:

package basic;

/**
 * 重点分析:
 * 一般来说,实例化的顺序像下面这样:
 * 1. 父类--静态变量
 * 2. 父类--静态初始化块
 * 3. 子类--静态变量
 * 4. 子类--静态初始化块
 * 5. 父类--变量
 * 6. 父类--初始化块
 * 7. 父类--构造器
 * 8. 子类--变量
 * 9. 子类--初始化块
 * 10. 子类--构造器
 * 
 * 但是注意!!如果静态属性实例化了自身,那么将不会调用他后面的静态物
 * 再注意!!如果静态属性实例化的其他类又回来实例化这个类,那么也还是不会调用他后面的静态物
 * 
 * @author Feng
 *
 */
public class Builder {
	private static int k = 0;
	private static int i = print("i");				//输出第1行
	private static Builder t1 = new Builder("t1");	//输出第2.3.4行,t1的构造流程不会调用后续的静态物
	private static Second ss = new Second();		//输出第5.6.7.8.9.10行,Second类回调的Builder对象依然不会调用后续的静态物	
	static {
		print("静态块1");								//输出第11行
	}
	private static Builder t2 = new Builder("t2");	//输出第12.13.14行,t2的构造流程和t1一样
	private static int n = 99;						//这个时候n才被设置成99,在此之前是从0开始的
	
	private int j = print("j");			//属性变量,每次构件对象都会调用,出现在2.6.12.17   
	
	{
		print("构造块");					//构造快,每次构件对象都会调用,出现在3.7.13.18
	}
	
	public Builder(String str){			//构造函数,最后才轮到构造函数来执行,分别在4.8.14.19
		System.out.println(++k + ":构造函数 " + str + "    i=" + i + "    n=" + n);
		i++;
		n++;
	}
	
	static {
		print("静态块2");					//输出第15行,终于轮到了
	}
	
	public static int print(String str){
		System.out.println(++k + ":" + str + "    i=" + i + "    n=" + n);
		n++;
		return ++i;
	}
	
	public static void main(String[] args){
		Builder b = new Builder("init");	//输出第17.18.19行,经历一系列初始化之后终于可以开始实例化对象了
		//Second.f1();		//如果不执行上一句,执行这句,唯一的不同就是少了最后3行输出,因为一旦调用了某个类的静态方法,这个类的初始化就要开始了
	}
	
	static {
		print("静态块3");					//输出第16行,静态块从此之后不会再初始化
	}
}


class Second{
	int s_j = Builder.print("s_j");						//执行3,输出第9行
	
	public Second(){
		Builder.print("Second 构造体");					//执行4,输出第10行				
	}
	
	static int s2 = Builder.print("Second");			//执行1,输出第5行
	
	static Builder s1 = new Builder("Second_Builder");	//执行2,输出第6.7.8行
	
	public static void f1(){
		
	}
}