最近在刷牛客网的题目看到有关静态代码块、构造代码块、构造方法的执行顺序的问题,因为基础不牢固没选出正确答案,当然要将这个知识点重新掌握,写篇博客来记录一下学习的过程。
  先了解一下相关概念:
  • 静态代码块:在类中以static关键字声明的代码块,随类的加载而执行
//父类静态代码块一
    static {
        System.out.println("父类静态代码块一,只会执行一次");
    }
  • 构造代码块:在类中以{}括起来的代码块,随对象的创建而执行
//父类构造代码块
    {
        System.out.println("父类构造代码块");
    }
  • 普通代码块:出现在方法中以{}括起来的代码块
{
       System.out.println("主方法中的普通代码块一");
    }
  • 构造方法:这个不解释了
  测试代码:
package com.youngpain;

class Parent {
    //父类静态代码块一
    static {
        System.out.println("父类静态代码块一,只会执行一次");
    }

    //父类静态成员变量
    private static int age = getAge();

    //父类普通成员变量
    private String car = getCar();

    //父类构造方法
    public Parent() {
        System.out.println("父类构造方法");
    }

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

    public String getCar() {
        System.out.println("父类普通成员变量初始化");
        return "Benz";
    }

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

    public static int getAge() {
        System.out.println("父类静态成员变量初始化");
        return 30;
    }

    //父类静态代码块二
    static {
        System.out.println("父类静态代码块二,只会执行一次");
    }

}

class Son extends Parent {
    //子类静态成员变量
    private static String name = getName();

    //子类构造方法
    public Son() {

        System.out.println("子类构造方法");
    }

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

    //子类静态代码块
    static {
        System.out.println("子类静态代码块,只会执行一次");
    }

    //子类普通成员变量
    private double height = getHeight();

    public static String getName() {
        System.out.println("子类静态成员变量初始化");
        return "Son";
    }

    public double getHeight() {
        System.out.println("子类普通成员变量初始化");
        return 1.65;
    }

}

public class LoadOrderTest {

    public static void main(String[] args) {
        {
            System.out.println("主方法中的普通代码块一");
        }
        System.out.println("创建第一个子类对象----------------------------");
        Son son1 = new Son();
        System.out.println("创建第二个子类对象----------------------------");
        Son son2 = new Son();
        {
            System.out.println("主方法中的普通代码块二");
        }
    }

}
  执行结果:
主方法中的普通代码块一
创建第一个子类对象----------------------------
父类静态代码块一,只会执行一次
父类静态成员变量初始化
父类静态代码块二,只会执行一次
子类静态成员变量初始化
子类静态代码块,只会执行一次
父类普通成员变量初始化
父类构造代码块一
父类构造代码块二
父类构造方法
子类构造代码块
子类普通成员变量初始化
子类构造方法
创建第二个子类对象----------------------------
父类普通成员变量初始化
父类构造代码块一
父类构造代码块二
父类构造方法
子类构造代码块
子类普通成员变量初始化
子类构造方法
主方法中的普通代码块二
  结果分析:
  • 先执行父类静态代码块和初始化父类的静态成员变量,如果有多个静态代码块,执行顺序取决于静态代码块的位置
  • 再执行子类静态代码块和初始化子类的静态成员变量,这里父类和子类中静态代码块和静态成员变量的位置相反,因此执行的顺序相反
  • 然后初始化父类普通成员变量,再执行父类构造代码块,如果有多个构造代码块,执行顺序取决于构造代码块的位置
  • 接着执行父类构造方法
  • 如果同时存在子类构造代码块和子类普通成员变量,谁在前就先执行或初始化
  • 最后执行子类的构造方法
  • 静态代码块和静态成员变量只会执行一次或初始化一次,构造代码块和普通成员变量每次创建对象都会执行或初始化
总结:

父类静态代码块(静态成员变量)>子类静态代码块(静态成员变量)>父类构造代码块(普通成员变量)>父类构造方法>子类构造代码块(普通成员变量)>子类构造方法

PS:个人总结,如有错误,敬请指正,不胜感谢!