当前位置: 代码迷 >> 综合 >> Java 类的加载顺序
  详细解决方案

Java 类的加载顺序

热度:54   发布时间:2024-02-05 18:16:36.0

今天来聊一聊Java类的加载顺序,话不多说,直接上干货。

public class Father {public static Print STATIC_COLUMN = new Print("父类静态字段1");public Print dynamicColumn = new Print("父类成员变量1");static{new Print("父类静态代码块");}{new Print("父类非静态代码块");}public Father(){new Print("父类无参数构造器");}public Father(Print print){new Print("父类有参构造器");}static class StaticInnerClz{static Print STATIC_COLUMN = new Print("父类静态内部类静态成员");public StaticInnerClz(){new Print("父类静态内部类构造器");}}public static Print STATIC_COLUMN2 = new Print("父类静态字段2");public Print dynamicColumn2 = new Print("父类成员变量2");
}public class Children extends Father{public static Print STATIC_COLUMN = new Print("子类静态字段1");public Print dynamicColumn = new Print("子类成员变量1");static{new Print("子类静态代码块");}{new Print("子类非静态代码块");}public Children(){new Print("子类无参数构造器");}public Children(Print print){new Print("子类有参构造器");}static class StaticInnerClz{static Print STATIC_COLUMN = new Print("子类静态内部类静态成员");public StaticInnerClz(){new Print("子类静态内部类构造器");}}public static Print STATIC_COLUMN2 = new Print("子类静态字段2");public Print dynamicColumn2 = new Print("子类成员变量2");
}

父子类的代码除了Print类的入参字符串,其他是一模一样的。

Print类是我写的一个方便打印的辅助类

public class Print {public String msg;public Print(String msg){this.msg = msg;System.out.println(msg);}
}
    public static void main(String[] args) {Children f = new Children(new Print("构造器入参"));}

 直接运行查看打印结果:

父类静态字段1
父类静态代码块
父类静态字段2
子类静态字段1
子类静态代码块
子类静态字段2
构造器入参
父类成员变量1
父类非静态代码块
父类成员变量2
父类无参数构造器
子类成员变量1
子类非静态代码块
子类成员变量2
子类有参构造器

分析结果我们可以发现:

  • 以"构造器入参"为分水岭,前半部分是静态资源加载,后半部分是动态资源加载。
  • 然后各自又存在父类优先于子类的加载顺序。
  • 构造器在最后才执行。
  • 从字段和代码块的加载顺序来看,是按照代码顺序来执行,并不存在优先级的差别。
  • 静态内部类在外部类初始化的过程中并不会同时初始化。

因此我们可以分析总结出如下规则:

  1. 静态优先于动态
  2. 父类优先于子类
  3. 字段优先于构造器

多条件情况下,按照1 > 2 > 3的规则执行。

接下来再做一下扩展,main方法增加一些代码:

    public static void main(String[] args) {Children f = new Children(new Print("构造器入参"));System.out.println("=====初始化结束======");Children f2 = new Children(new Print("再次初始化,构造器入参"));System.out.println("=====初始化结束======");Children.StaticInnerClz innerClz = new Children.StaticInnerClz();}

运行查看结果:

父类静态字段1
父类静态代码块
父类静态字段2
子类静态字段1
子类静态代码块
子类静态字段2
构造器入参
父类成员变量1
父类非静态代码块
父类成员变量2
父类无参数构造器
子类成员变量1
子类非静态代码块
子类成员变量2
子类有参构造器
=====初始化结束======
再次初始化,构造器入参
父类成员变量1
父类非静态代码块
父类成员变量2
父类无参数构造器
子类成员变量1
子类非静态代码块
子类成员变量2
子类有参构造器
=====初始化结束======
子类静态内部类静态成员
子类静态内部类构造器

分析结果我们可以发现:

  • 再次初始化一个新的子类对象时,不再加载静态成员,静态代码块。
  • 静态内部类和外部类一样需要程序员触发调用才开始初始化。(启动类由JVM触发加载)