前置知识

  • 初始化块:类中直接用 {} 定义,每一次创建对象时执行
  • 静态代码块:用 staitc 声明,JVM加载类时执行,仅执行一次

Java 程序初始化顺序

对于静态变量、静态初始化块、变量、初始化块、构造器,它们初始化顺序流程如下文字描述,示意图如下

静态变量、静态代码块 > 变量、初始化块 > 构造器

静态变量和静态代码块两个的初始化顺序是靠它们俩的位置决定的

运行初始化命令yarn install 初始化程序代码_System

单个类的初始化

单个类的初始化

public class Example {

    public static String STR = "静态成员变量";

    public String variable = "普通成员变量";

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

    {
        System.out.println(variable);
        System.out.println("初始化块");
    }

    public Example(){
        System.out.println("构造器");
    }

    public static void main(String[] args) {
        System.out.println("Java 程序初始化顺序");
        Example a = new Example();
    }
}

结果

静态成员变量
静态代码块
Java 程序初始化顺序
普通成员变量
初始化块
构造器

调换静态成员变量和静态代码块顺序

静态成员变量在先,并做初始化动作

public class Example {

    public static Example example1 = new Example();
    public static Example example2 = new Example();

    {
        System.out.println("构造块");
    }

    static {
        System.out.println("静态块");
    }

    public Example(){
        System.out.println("构造器");
    }

    public static void main(String[] args) {
        System.out.println("Java初始化顺序");
        Example example = new Example();
    }
}

结果

构造块  ---->(example1实例)
构造器  ---->(example1实例)
构造块  ---->(example2实例)
构造器  ---->(example2实例)
静态块
Java初始化顺序
构造块  ---->(example实例)
构造器  ---->(example实例)

静态成员变量在后,并做初始化动作

public class Example {

    public Example(){
        System.out.println("构造器");
    }

    {
        System.out.println("构造块");
    }

    static {
        System.out.println("静态块");
    }

    public static Example example1 = new Example();
    public static Example example2 = new Example();

    public static void main(String[] args) {
        System.out.println("Java初始化顺序");
        Example example = new Example();
    }
}

结果

静态块
构造块  ---->(example1实例)
构造器  ---->(example1实例)
构造块  ---->(example2实例)
构造器  ---->(example2实例)
Java初始化顺序
构造块  ---->(example实例)
构造器  ---->(example实例)

静态变量在前,并不做初始化

public class Example {

    public static Example example1;
    public static Example example2;

    {
        System.out.println("构造块");
    }

    static {
        System.out.println("静态块");
    }

    public Example(){
        System.out.println("构造器");
    }

    public static void main(String[] args) {
        System.out.println("Java初始化顺序");
        Example example = new Example();
    }
}

结果

静态块
Java初始化顺序
构造块  ---->(example实例)
构造器  ---->(example实例)

具有继承关系的初始化

父类

public class Father {

    public static String F_STR = "父类-静态成员变量";

    public String f_variable = "父类-普通成员变量";

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

    {
        System.out.println(f_variable);
        System.out.println("父类-初始化块");
    }

    public Father(){
        System.out.println("父类-构造器");
    }
}

子类

public class Subclass extends Father{

    public static String S_STR = "子类-静态成员变量";

    public String s_variable = "子类-普通成员变量";

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

    {
        System.out.println(s_variable);
        System.out.println("子类-初始化块");
    }

    public Subclass(){
        System.out.println("子类-构造器");
    }

    public static void main(String[] args) {
        System.out.println("Java 程序初始化顺序");
        Subclass subclass = new Subclass();
    }
}

结果

父类-静态成员变量
父类-静态代码块
子类-静态成员变量
子类-静态代码块
Java 程序初始化顺序
父类-普通成员变量
父类-初始化块
父类-构造器
子类-普通成员变量
子类-初始化块
子类-构造器

初始化说明

  1. 访问子类的main(),于是装载器就会寻找已经编译的子类class文件。在装载的过程中,装载器注意到它有一个基类,于是它再装载基类。不管创不创建基类对象,这个过程总会发生。如果基类还有基类,那么第二个基类也会被装载,依此类推
  2. 执行根基类的static初始化,然后是下一个派生类的static初始化,依此类推。这个顺序非常重要,因为派生类的static初始化有可能要依赖基类成员的正确初始化
  3. 当所有必要的类都已经装载结束,开始执行main()方法体,并用new Subclass()创建对象
  4. 类Subclass存在父类,则调用父类的构造函数,可以使用super来指定调用哪个构造函数
  1. 基类的构造过程以及构造顺序,同派生类的相同。首先基类中各个变量按照字面顺序进行初始化,然后执行基类的构造函数的其余部分
  1. 对子类成员数据按照它们声明的顺序初始化,执行子类构造函数的其余部分

不会初始化子类情况

不会初始化子类的情况

public class Father {
    
    public static int number = 123;

    public static final int number2 = 456;
    
    static{
        System.out.println("父类-静态代码块");
    }

    {
        System.out.println("父类-构造块");
    }

    public Father(){
        System.out.println("父类-构造器");
    }
}

 class Subclass extends Father {
     
    static{
        System.out.println("子类-静态代码块");
    }

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

     public Subclass(){
         System.out.println("子类-构造器");
     }
}

class Test {
    public static void main(String[] args) {
        System.out.println(Subclass.number);
        System.out.println("-------------------------");
        System.out.println(Subclass.number2);
        System.out.println("-------------------------");
        Subclass[] s = new Subclass[10];
    }
}

结果

父类-静态代码块
123
-------------------------
456
-------------------------