Java 静态代码块、代码块、构造函数、静态Field声明执行顺序
1.首先有个SuperClass:
public class SuperClass {
static {
System.out.println("父类的静态代码块");
}
{
System.out.println("父类代码块");
}
public SuperClass() {
System.out.println("父类的构造函数");
}
}
这个类有静态的代码块,代码块,构造函数
2. 有个SuperClass的子类:
public class StaticCodeBlockClass extends SuperClass {
public static int b = 1;
static {
a = 6;
b = 2;
System.out.println("子类静态代码块");
}
public static int a = 9;
{
System.out.println("子类代码块");
}
public StaticCodeBlockClass() {
System.out.println("子类构造函数");
}
}
也有静态代码块,代码块,构造函数。
3. 还有一个测试无关的类:
public class NormalClass {
public NormalClass() {
System.out.println("我是一个无关类,我要初始化了");
}
}
4.我们执行下面的代码:
public static void main(String[] args) {
System.out.println("--------应用开始启动-----------");
NormalClass normalClass = new NormalClass();
System.out.println("--------第一次使用-----------");
//第一次是使用StaticCodeBlockClass,要进行类的准备阶段,进行类变量分配内存。然后进行初始化阶段(执行类的静态代码块)
StaticCodeBlockClass staticCodeBlockClass1 = new StaticCodeBlockClass();
System.out.println("a="+StaticCodeBlockClass.a);
System.out.println("b="+StaticCodeBlockClass.b);
System.out.println("--------第二次使用-----------");
//第二次执行就不需要进行类的准备阶段和类初始化阶段 直接进行实例的初始化。
StaticCodeBlockClass staticCodeBlockClass2 = new StaticCodeBlockClass();
}
5.得到下面的结果:
--------应用开始启动-----------
我是一个无关类,我要初始化了
--------第一次使用-----------
父类的静态代码块
子类静态代码块
父类代码块
父类的构造函数
子类代码块
子类构造函数
a=9
b=2
--------第二次使用-----------
父类代码块
父类的构造函数
子类代码块
子类构造函数
因此我们得到下面的结论:
- 类的准备阶段和初始化阶段是我们在应用中第一次使用该类的时候才进行。(应用开始进行NormalClass的时候并没有进行StaticCodeBlock的初始化)
- 类的静态代码块只有第一次进行类的初始化阶段执行。并且是先执行父类再执行子类。(第二次初始化StaticCodeBlock的时候就没有再次执行类的静态块)
- 代码块是先执行父类再执行子类。
- 构造函数是先执行父类再执行子类。
- 实例的代码块比构造函数先执行。
- 父类的代码块和构造函数都执行完了才执行子类的代码块和构造函数。(可以理解为执行构造函数之前要执行实例代码块)
- 在类的初始化阶段是要执行类的静态代码块和Field的声明,这二者的执行顺序是按照源代码的排列顺序执行的。注意StaticCodeBlockClass 的静态Field a,b的值的输出。
-
(staicic 的代码块是类的代码块,非static的代码块是实例的代码块)