jvm虚拟机类加载机制详解
什么是类加载
在 Java 程序中,类的加载是指将类的 .class 文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后在堆区创建一个 java.lang.Class
对象,用来封装在方法区内的数据结构。ClassLoader 类是用来加载 Java 类的类加载器。
类加载的步骤
Java 虚拟机将符号引用转换成直接引用的过程分为以下 5 个阶段。
-
加载:在这个阶段,ClassLoader 会通过全限定名来读取 .class 文件,并生成对应的字节数组。
-
链接:在加载阶段后,虚拟机会将这个类的二进制数据中的符号引用替换成直接引用,包括以下三个阶段:
-
验证:这个阶段确保所导入的类是能够正确执行,且与当前运行环境的其他代码并存是安全的。在这个阶段中,将会检查 .class 文件的合法性,并且验证类中的各种信息是否符合 Java 虚拟机规范,例如类是否继承于指定的类或实现了接口。
-
准备:为类变量(static 变量)分配内存,设置初始值。
-
解析:将符号引用转换成直接引用。
-
初始化:当 Java 程序运行至这个阶段时,就会执行类构造器
<clinit>
方法的内容,为类静态变量分配内存并设置初始值,这些静态变量所使用的值在代码中是已经明确写好的,因而在这个时候称为确定值。也就是说,在初始化阶段,类变量的初始化是实际被执行的操作,并且是在这个阶段对其赋值的。对于实例变量的初始化,是在对象实例化时进行的。
示例说明
示例一
下面的代码演示了类的初始化顺序。
public class Example {
public static void main(String[] args) {
new SubClass();
}
}
class SuperClass {
static {
System.out.println("SuperClass init");
}
}
class SubClass extends SuperClass {
static {
System.out.println("SubClass init");
}
}
输出结果为:
SuperClass init
SubClass init
在以上代码中,main
方法创建了一个 SubClass
的实例。在这个过程中,会触发对 SubClass
类的初始化,而 SubClass
继承自 SuperClass
,因此会先初始化 SuperClass
类。
示例二
下面的代码演示了类的动态加载。
public class Example {
public static void main(String[] args) throws Exception {
Class clazz = Class.forName("com.example.SubClass");
System.out.println(clazz.getClassLoader());
}
}
class SubClass {
}
输出结果为:
sun.misc.Launcher$AppClassLoader@18b4aac2
在以上代码中,main
方法加载了 SubClass
类,并输出其类加载器。总结一下以上示例:
- 当访问类的静态变量时,会触发对该类的初始化。
- 当通过
Class.forName
方法加载类时,也会触发对该类的初始化。 - 类的加载由实现类消除,可以通过重写 systemClassLoader 完成。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:jvm虚拟机类加载机制详解 - Python技术站