Java中类的加载顺序

以前对类的加载顺序,静态变量的初始化,普通变量的初始化,构造函数的初始化,构造代码块,静态代码块的初始化顺序一直搞不清楚,于是乎今天特别的做了一下,记录。
为了完成今天的测试,先给出测试类。

1.测试类

  • 父类
public class Father {
    
    static String staticVar1 = LoaderUtils.getMemberValue("[父类]静态变量1");
    static String staticVar2 = LoaderUtils.getMemberValue("[父类]静态变量2");
    
    String normalVar1 = LoaderUtils.getMemberValue("[父类]普通变量1");
    String normalVar2 = LoaderUtils.getMemberValue("[父类]普通变量2");

    {
        System.out.println("[父类]匿名构造函数初始化");
    }
    
    static {
        System.out.println("[父类]静态匿名构造函数初始化");
    }

    Father() {
        System.out.println("[父类]无参构造函数初始化");
    }

}
  • 子类
public class Son extends Father {

    static String staticVar1 = LoaderUtils.getMemberValue("[子类]静态变量1");
    static String staticVar2 = LoaderUtils.getMemberValue("[子类]静态变量2");

    String normalVar1 = LoaderUtils.getMemberValue("[子类]普通变量1");
    String normalVar2 = LoaderUtils.getMemberValue("[子类]普通变量2");

    {
        System.out.println("[子类]匿名构造函数初始化");
    }

    static {
        System.out.println("[子类]静态匿名构造函数初始化");
    }

    public Son() {
        System.out.println("[子类]无参构造函数初始化");
    }
}
  • LoaderUtils:用于对静态,非静态成员变量进行赋值和控制台输出。
public class LoaderUtils {
    public static String getMemberValue(String input) {
        System.out.println(input);
        return input;
    }
}
  • 客户端
public static void main(String[] args) {
        System.out.println("***************第[1]次调用构造函数**************");
        Son son1 = new Son();
        System.out.println("***************第[2]次调用构造函数**************");
        Son son2= new Son();
        System.out.println("***************第[3]次调用构造函数**************");
        Son son3 = new Son();
    }
  • 输出结果
***************第[1]次调用构造函数**************
[父类]静态变量1
[父类]静态变量2
[父类]静态匿名构造函数初始化
[子类]静态变量1
[子类]静态变量2
[子类]静态匿名构造函数初始化
[父类]普通变量1
[父类]普通变量2
[父类]匿名构造函数初始化
[父类]无参构造函数初始化
[子类]普通变量1
[子类]普通变量2
[子类]匿名构造函数初始化
[子类]无参构造函数初始化
***************第[2]次调用构造函数**************
[父类]普通变量1
[父类]普通变量2
[父类]匿名构造函数初始化
[父类]无参构造函数初始化
[子类]普通变量1
[子类]普通变量2
[子类]匿名构造函数初始化
[子类]无参构造函数初始化
***************第[3]次调用构造函数**************
[父类]普通变量1
[父类]普通变量2
[父类]匿名构造函数初始化
[父类]无参构造函数初始化
[子类]普通变量1
[子类]普通变量2
[子类]匿名构造函数初始化
[子类]无参构造函数初始化

2.结果分析

在本例中Son继承Father,并且在子,父类中分别定义了,静态变量,静态代码块,普通变量,构造代码块和构造函数。
由结果可以看出,在第一次调用构造函数的过程中,虽然子类Son没有显示的调用父类的无参构造,但是Java会帮我们完成调用父类无参构造的过程。

  • 静态代码只会执行一次。
    从上面3次的输出结果可以看出,静态代码的初始化只有第一次new对象的时候会执行,之后再new对象则不再执行静态代码的初始化。
  • 静态优于非静态
    并且静态代码要优先于非静态代码先执行初始化。
  • 父类初始化先于子类初始化。
    在本例中,无论是静态还是非晶态资源的初始化,父类的初始化动作总是先于子类的初始化。
  • 初始化顺序和声明顺序相同
    无论是静态代码块,静态变量 。还是普通变量,构造代码块。他们的执行顺序和他们再类中的声明顺序有关,在前面的先执行,在后面的后执行。
  • 构造函数总是在最后执行。

总结下来就是

  • 先静态后普通。
  • 先父类后子类。
  • 静态,非静态资源的初始化顺序等于其声明顺序。
  • 构造函数总在最后执行。

你可能感兴趣的:(Java中类的加载顺序)