JavaSE学习过程中,笔者一直在这一块纠结,总是理解的一知半解,静态代码块和构造代码块的执行顺序到底是什么样的,花了很久的时间,现在把我到目前为止理解的情况记录下来
- 局部代码块
局部代码块就是定义用{}划定的区域,其作用的区域在方法中,只是起到了划分作用域的作用。 - 构造代码块
构造代码块定义在类中成员位置上,优先于构造方法执行,每创建一个对象均会执行一次构造代码块。
这里笔者通过验证,发现:构造代码块虽然会优先于构造方法执行,但是它是在本类构造方法中默认的父类构造方法执行完后才会执行
class Fu {
{
System.out.println("1");
}
public Fu(){
System.out.println("a");
}
}
class Zi extends Fu {
{
System.out.println("2");
}
public Zi(){
System.out.println("b");
}
}
class Demo {
public static void main(String[] args) {
Fu f = new Zi();
}
}
上述代码运行的结果是:1a2b,即等父类构造代码块与构造方法执行完,再执行之类的构造代码块与构造方法。
笔者之前一直觉得结果应该是:21ab(因为认为super()这个默认的调用父类构造方法在本类构造方法中,应该在本类的构造代码块后面执行)
是因为笔者没有深刻理解构造代码块会优先与构造方法执行的真正含义,因为Java是有分层初始化机制的,子类必须在父类初始化完以后才能初始化(构造方法执行)
4. 静态代码块
静态代码块也是定义在成员位置上,使用static修饰。
因为静态代码块有static修饰,因此,可以知道这个代码块是在类加载的过程中就执行的,也就是说静态代码块的执行优先于对象的创建。
`
public class Test {
public static void main(String[] args) {
Son son = new Son();
}
}
class Father{
static {
System.out.println("父静态代码块"); //1
}
{
System.out.println("父构造代码块"); //3
}
Father(){
System.out.println("父构造方法"); //4
}
}
class Son extends Father{
static {
System.out.println("子静态代码块"); //2
}
{
System.out.println("子构造代码块"); //5
}
Son(){
System.out.println("子构造方法"); //6
}
}`
首先,JVM调用了main方法,main方法进栈,此时遇到Son son = new Son()这句语句,会将Father.class和Son.class分别加载进内存,之后才会创建对象。我们知道,静态代码块的执行优先于对象的创建,也就是说当Father.class加载进内存时,父类的静态代码块会随着Father.class一起加载,然后是Son.class加载进内存,而与此同时子类的静态代码块也会随着Son.class一起加载进内存。
接着将会执行子类的构造方法,而由于分层初始化的机制,需要先初始化父类,再初始化子类,于是这段代码的结果就是:
父类静态代码块
子类静态代码块
父类构造代码块
父类构造方法
子类构造代码块
子类构造方法