今天来聊一聊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的规则执行。
接下来再做一下扩展,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触发加载)
版权声明:本文为qq_36389344原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。