package com.initialization.order;
class Bowl {
Bowl(){
System.out.println("Bowl(9)");
}
Bowl(int marker) {
System.out.println("Bowl(" + marker + ")");
}
static Bowl b6 = new Bowl(6);
static Bowl b9 = new Bowl();
void f(int marker) {
System.out.println("f(" + marker + ")");
}
}
class Table {
static Bowl b1 = new Bowl(1);
Table() {
System.out.println("Table()");
b2.f(1);
}
void f2(int marker) {
System.out.println("f2(" + marker + ")");
}
static Bowl b2 = new Bowl(2);
}
class Cupboard {
Bowl b3 = new Bowl(3);
Bowl b10 = new Bowl();
static Bowl b4 = new Bowl(4);
Cupboard() {
System.out.println("Cupboard()");
b4.f(2);
}
void f3(int marker) {
System.out.println("f3(" + marker + ")");
}
static Bowl b5 = new Bowl(5);
}
public class StaticInitialization {
//static Bowl b7 = new Bowl(7); //----------(1)
public static void main(String[] args) {
System.out.println(
"Creating new Cupboard() in main");
new Cupboard();
System.out.println(
"Creating new Cupboard() in main");
new Cupboard();
//t2.f2(1); //--------------(2)
//t3.f3(1); //---------------(3)
}
//static Bowl b8 = new Bowl(8); //----------------(4)
//static Table t2 = new Table(); //----------------(5)
//static Cupboard t3 = new Cupboard(); //---------(6)
} ///:~
调试以上代码,总结出以下结论:
一、初始化的过程:总体来说顺序为:static初始化->非static初始化->执行构造函数;
二、代码分析一:对现有代码执行结果如下:
Creating new Cupboard() in main
Bowl(6)
Bowl(9)
Bowl(4)
Bowl(5)
Bowl(3)
Bowl(9)
Cupboard()
f(2)
Creating new Cupboard() in main
Bowl(3)
Bowl(9)
Cupboard()
f(2)
执行过程:
1、java解释器寻找public class类,加载StaticInitialization 类;
2、寻找StaticInitialization 类中的static定义代码段;这里因为(1)、(4)、(5)、(6)均加了注释,所以StaticInitialization 中没有static需要初始化;
3、进入main函数中执行代码输出Creating new Cupboard() in main;
4、继续执行new Cupboard();,注意初始化的顺序是static初始化->非static初始化->执行构造函数;所以加载类Cupboard后,首先寻找Cupboard类中的static代码段;
发现static段是: static Bowl b4 = new Bowl(4); static Bowl b5 = new Bowl(5);
同时发现有非static段是: Bowl b3 = new Bowl(3); Bowl b10 = new Bowl();
按顺序先执行:static Bowl b4 = new Bowl(4); 初始化,因为定义的是Bowl类的实例,所以先加载Bowl类,进入Bowl类发现又有static代码段static Bowl b6 = new Bowl(6);
static Bowl b9 = new Bowl();然而我们知道初始化static Bowl b4 = new Bowl(4); 需要调用Bowl 的构造函数,但调用构造函数之前必须将该类需要初始化的部分先进行初始化,所以执行到这里就要先进行Bowl类中的static代码段的初始化,之后才能调用构造函数Bowl(int marker) 为static Bowl b4 = new Bowl(4); 进行初始化。于是b6,b9分别调用构造函数Bowl(int marker),Bowl(),输出Bowl(6),Bowl(9),完了之后,b4调用构造函数Bowl(int marker)输出Bowl(4),b4初始化结束,返回Cupboard类继续执行,初始化b5,输出Bowl(5),此时Cupboard类中static部分初始化完,接下来对非static部分初始化,即对b3和b10初始化,一样的方法,加载Bowl类,发现static字段在上面已经初始化,所以这里直接调用Bowl类的构造函数,输出Bowl(3),Bowl(9)。至此Cupboard类中需要初始化的部分已经初始化完了,所以放心大胆的调用Cupboard类的构造函数,为main函数中代码完成new Cupboard();的实现,输出Cupboard(),f(2)。程序执行返回到main函数,输出:Creating new Cupboard() in main,代码new Cupboard();又一次出现,这里实际上是想演示static只会初始化一次,而非static只要创建了对象或调用了成员、成员函数,会进行第二次初始化,于是可以看到输出结果并没有再输出Bowl(6)、Bowl(9)、Bowl(4)、Bowl(5),而是输出:Bowl(3)、Bowl(9)、Cupboard()、f(2)。
5、取消注释(1)、(4),发现结果如下:
Bowl(6)
Bowl(9)
Bowl(7)
Bowl(8)
Creating new Cupboard() in main
Bowl(4)
Bowl(5)
Bowl(3)
Bowl(9)
Cupboard()
f(2)
Creating new Cupboard() in main
Bowl(3)
Bowl(9)
Cupboard()
f(2)
可以看出输出了Bowl(7)、Bowl(8),这说明在main()函数执行之前,程序要先对StaticInitialization进行检查,如果有static部分,则先初始化。
6、再取消注释(2)、(5)输出结果为:
Bowl(6)
Bowl(9)
Bowl(7)
Bowl(8)
Bowl(1)
Bowl(2)
Table()
f(1)
Creating new Cupboard() in main
Bowl(4)
Bowl(5)
Bowl(3)
Bowl(9)
Cupboard()
f(2)
Creating new Cupboard() in main
Bowl(3)
Bowl(9)
Cupboard()
f(2)
f2(1)
在前面的基础上又输出了Bowl(1)、Bowl(2)、Table()、f(1)。然而我们看到当没有代码
static Table t2 = new Table();的时候Table类中的static部分没有被初始化,这说明什么?
static初始化只有在必要的时候才会进行。只有在创建了第一个Table对象之后才会进行初始化。
总结如下:初始化顺序为:加载public StaticInitialization类->初始化static->加载类Cupboard->初始化static->加载类Bowl->初始化static->执行Bowl类构造函数->初始化Cupboard类非static->调用Bowl类构造函数执行->调用Cupboard类构造函数执行->返回StaticInitialization类.