java类加载与实例化顺序

类加载与实例化

初始化块

实际上,初始化块是一个假象,使用javac命令编译java类后,初始化块会消失,初始化代码被还原到每个构造器中代码的最前面

  • 前面的初始化块先执行,后面的后执行
  • 初始化块的修饰符只能是 static
  • 普通初始化块负责对对象执行初始化,静态初始化块负责对类执行初始化
  • 初始化块只在创建java对象时隐式的执行,在构造器之前执行

当java创建对象时,初始化顺序是:

  1. 第一次类加载时:
    先执行顶层父类的静态初始化代码,再向下追溯执行间接父类静态初始化代码,
    最后执行直接父类静态初始化代码;
    静态初始化块和声明静态成员变量时指定的初始值都是给类的静态初始化代码,
    它们的执行顺序与源码中书写顺序相同。

  2. 接着开始对对象实例化
    先执行初始化块或声明实例变量时指定的初始值(两者执行顺序与源码书写顺序相同),
    再执行构造器里的代码。

class Root{
	static {
		System.out.println("Root的静态初始化块");
	}
	
	{
		System.out.println("Root的普通初始化块");
	}
	
	public Root() {
		System.out.println("Root的无参构造器");
	}
	
}

class Mid extends Root{
	static {
		System.out.println("Mid的静态初始化块");
	}
	
	{
		System.out.println("Mid的普通初始化块");
	}
	
	public Mid() {
		System.out.println("Mid的无参构造器");
	}
	
	public Mid(String msg) {
		this();
		System.out.println("Mid的带参构造器,其参数值:" + msg);
	}
	
}

class Leaf extends Mid{
	static {
		System.out.println("Leaf的静态初始化块");
	}
	
	{
		System.out.println("Leaf的普通初始化块");
	}
	
	public Leaf() {
		super("疯狂java");
		System.out.println("Leaf的无参构造器");
	}
}

public class Test {
	public static void main(String[] args){
		new Leaf();
		new Leaf();
	}
}

执行流程:
程序执行流程:
类加载:
打印 Root的静态初始化块 -->
打印 Mid的静态初始化块 -->
打印 Leaf的静态初始化块 -->
回到Test类new Leaf()准备实例化 -->
进入Leaf无参构造 -->
执行super进入Mid有参构造 -->
执行this进入MId无参构造 -->
执行super进入Root无参构造 -->
进入Root初始化块执行打印 -->
进入Super无参构造并执行打印 -->
进入Mid普通初始化块执行打印 -->
进入MId无参构造并执行打印 -->
进入Mid有参构造执行打印 -->
进入Leaf初始化块打印 -->
进入Leaf无参构造打印 --> …

执行结果:

Root的静态初始化块
Mid的静态初始化块
Leaf的静态初始化块
Root的普通初始化块
Root的无参构造器
Mid的普通初始化块
Mid的无参构造器
Leaf的普通初始化块
Leaf的无参构造器
Root的普通初始化块
Root的无参构造器
Mid的普通初始化块
Mid的无参构造器
Leaf的普通初始化块
Leaf的无参构造器

你可能感兴趣的:(java基础)