java运行时,jvm会对用到的类进行加载。那么,类加载的顺序是什么呢?
下面使用parent、child1、child2三个类验证,类在继承和调用时,各个类的静态初始化块、非静态初始化块和构造方法的加载顺序。
Parent:
public class Parent {
/**
*
*/
public Parent() {
// TODO Auto-generated constructor stub
System.out.println("父类构造方法");
}
static {
System.out.println("父类静态初始化块");
}
{
System.out.println("父类非静态初始化块");
}
}
Child1:
public class Child1 extends Parent {
/**
*
*/
public Child1() {
// TODO Auto-generated constructor stub
System.out.println("子类1构造方法");
}
static {
System.out.println("子类1静态初始化块");
}
{
System.out.println("子类1非静态初始化块");
}
//调用child2
Child2 child2 = new Child2();
}
Child2
public class Child2 {
/**
*
*/
public Child2() {
// TODO Auto-generated constructor stub
System.out.println("子类2构造方法");
}
static {
System.out.println("子类2静态初始化块");
}
{
System.out.println("子类2非静态初始化块");
}
}
运行结果:
父类静态初始化块
子类1静态初始化块
父类非静态初始化块
父类构造方法
子类1非静态初始化块
子类2静态初始化块
子类2非静态初始化块
子类2构造方法
子类1构造方法
子类2非静态初始化块
子类2构造方法
从运行结果分析,可以得到如下结论:
- 类中加载顺序:静态初始化块>非静态初始化块>构造方法;
- 涉及到继承时:父类静态初始化块>子类静态初始化块>父类非静态初始化块>父类构造方法>子类非静态初始化块>子类构造方法;
- 涉及到调用时:调用方A静态初始化块>A非静态初始化块>被调用方B静态初始化块>B非静态初始化块>B构造方法>A构造方法;
- 测试中,调用了两次Child2,但是其静态初始化块只被加载了一次。利用jvm的这个特性,在程序设计时,多考虑静态初始化块的写法,可以帮助我们提高程序运行效率。
- 若有变量,变量与代码块同等级,但应先于代码块;
注:本次测试是在普通类的基础上进行的,仅验证jvm对普通类的加载顺序,内部类的情况另作讨论