对象创建时的代码执行顺序

1,742 阅读2分钟

梳理下Java中对象创建时的加载顺序

public class B extends A {
    static C c = new C();

    static {
    	System.out.println("子类静态代码块");
    }    

    {
    	System.out.println("子类构造代码块");
    }

    public B(){
        System.out.println("子类构造函数");
    }
    
    public static void main(String[] args) {
    	B b = new B();
    }
}

class A {
	static {
    	System.out.println("父类静态代码块");
    }
    
    {
    	System.out.println("父类构造代码块");
    }
    
    public A(){
        System.out.println("父类构造函数");
    }
}

class C {
    static {
    	System.out.println("静态代码块");
    }
    
    {
    	System.out.println("构造代码块");
    }
    
    public C(){
        System.out.println("构造函数");
    }
}

控制台输出

父类静态代码块
静态代码块
构造代码块
构造函数
子类静态代码块
父类构造代码块
父类构造函数
子类构造代码块
子类构造函数

对象创建时,代码运行顺序(优先级): 父类静态代码块 -> 子类静态代码块 -> 父类构造代码块 -> 父类构造函数 -> 子类构造代码块 -> 子类构造函数

  1. 父类先于子类进行初始化;
  2. classloader懒加载, 类被调用时才会加载类
  3. 静态变量与静态代码块随着类被加载而调用
  4. 实例成员变量和代码块随着对象初始化(new或反射创建对象)而调用
  5. 静态变量的优先级与静态代码块等同, 实例成员变量的优先级与构造代码块等同。
  6. 如果类中同时有静态变量和静态代码块,执行顺序按照代码编写顺序先后。

为什么构造代码块先于构造函数运行?

javac 将XXX.java编译成XXX.class时会将构造代码块插入到构造函数之前。

反编译  A.class 
...
    public A(){
        System.out.println("父类构造代码块");
        System.out.println("父类构造函数");
    }
...
public class B
{
    public static B t1 = new B();
    public static B t2 = new B();
    {
        System.out.println("构造块");
    }
    static
    {
        System.out.println("静态块");
    }
    public static void main(String[] args)
    {
        B t = new B();
    }
}
输出顺序为:  构造块 静态块 构造块 构造块