Java中类的加载顺序剖析(常用于面试题)

  

Java中类的加载顺序剖析

在Java中,类的加载顺序是一个很重要的概念,也是经常出现在面试题中的一个考点。本文将会详细讲解Java中类的加载顺序,并且提供相关的代码示例。

类的生命周期

在深入讲解类的加载顺序之前,我们需要先了解Java中类的生命周期。Java中类的生命周期分为五个部分:加载、验证、准备、解析、初始化。

  1. 加载:在该阶段,Java虚拟机将会从class文件中读取类的二进制数据,并且将其转换成一个Class对象,并存储在方法区中。
  2. 验证:在该阶段,Java虚拟机将会对class文件进行合法性的校验,包括文件格式的校验、语义的校验等。
  3. 准备:在该阶段,Java虚拟机将会为类的静态变量分配内存,并设置默认值(零值)。
  4. 解析:在该阶段,Java虚拟机将会将类的符号引用转换成直接引用。
  5. 初始化:在该阶段,Java虚拟机将会执行类的初始化操作,包括执行静态变量的显式赋值、执行静态代码块等。

类的加载顺序

在了解了类的生命周期之后,我们可以开始了解类的加载顺序了。类的加载顺序分为三个步骤:父类的加载、静态变量的初始化、静态代码块的执行。

  1. 父类的加载:先加载父类,再加载子类。
  2. 静态变量的初始化:按照代码中的顺序对静态变量进行初始化。
  3. 静态代码块的执行:按照代码中的顺序执行静态代码块。

下面我们来看两个示例,更好地理解类的加载顺序。

示例一

public class Father {
    public static int a = 1;

    static {
        System.out.println("Father static block");
    }
}

public class Son extends Father {
    public static int b = 2;

    static {
        System.out.println("Son static block");
    }
}

public class LoadOrderTest {
    public static void main(String[] args) {
        System.out.println(Son.b);
    }
}

运行结果:

Father static block
Son static block
2

解释:由于Son类继承自Father类,所以在Son类加载之前需要先加载Father类,在加载Father类的时候,执行了Father的静态代码块,输出了"Fther static block",然后加载Son类,执行了Son的静态代码块,输出了"Son static block",最后输出了Son类的静态变量b的值2。

示例二

public class Father {
    public static int a = 1;

    static {
        System.out.println("Father static block");
    }
}

public class Son extends Father {
    public static int b = 2;

    static {
        System.out.println("Son static block");
    }

    public static void main(String[] args) {
        System.out.println(b);
    }
}

运行结果:

Father static block
Son static block
2

解释:由于Son类继承自Father类,所以在Son类加载之前需要先加载Father类,在加载Father类的时候,执行了Father的静态代码块,输出了"Fther static block",然后加载Son类,执行了Son的静态代码块,输出了"Son static block",最后执行了Son类的main方法,输出了Son类的静态变量b的值2。

结论

Java中类的加载顺序非常的重要,在开发过程中需要注意类的继承关系、静态变量和静态代码块的初始化顺序,避免一些难以发现的bug。

相关文章