JVM(Java Virtual Machine),即Java虚拟机。Java之所以拥有跨平台的能力,JVM在其中有着举足轻重的地位。
JVM的类加载机制是指:JVM把描述类的数据从Class文件加载到内存,并对数据进行校验、转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型。
其实整个加载过程,主要有三大步,分别是:加载、链接、初始化。接下来,我将分别进行阐述。
第一步、加载
首先从不同的数据源(可以是class文件、jar包,网络、数据库等等符合class文件结构的来源)将二进制字节码加载到JVM内存中,并映射为JVM可用的数据结构(Class对象)。如果加载的不是Class文件类型,则会抛出java.lang.ClassFormatError。
加载阶段的可控性非常强,我们开发人员可以使用系统提供的相关类加载器(启动类加载器、扩展类加载器和应用程序类加载器),也可以自定义类加载器来实现我们想要的功能,比如阿里的热修复框架AndFix就利用自定义类加载器来加载修复包文件。
第二步、链接
在这一步,又可以细分为:验证、准备、解析三个阶段。
-
验证
对加载进来的二进制字节码进行验证,检查是否符合JVM的规范,如果验证失败,则会抛出java.lang.VerifyError。该操作可有效保障JVM的安全,防止进行恶意操作。
-
准备
创建类或接口中的静态变量,并初始化静态变量的初始值,以及在方法区分配所需的内存空间。
上面所讲的静态变量是指被static修饰的变量,不包括实例变量,如下代码:
public static int result = 666;
该静态变量经过准备阶段之后,初始值是0,而不是666。因为这里只分配了内存,并没有执行其他的JVM指令。但是也有一种特殊情况,如下代码:
public static final int result = 666;
此时,result被final修饰,*.java文件经过Javac编译后,就会在该字段的属性表中生成ConstantValue属性,并在准备阶段的时候,JVM就会根据ConstantValue的设置将result赋值为666。
-
解析
在这一步JVM会将常量池中的符号引用转换为直接引用。
这里的符号引用和直接引用的区别:
符号引用:符号引用是以一组符号来描述所引用的目标,符号并没有具体的命名规范要求,只要没有歧义就行。与JVM实现的内存布局无关,并且引用的目标不一定存在于内存中。
直接引用:直接引用可以是直接指向目标的指针、相对偏移量或是一个能间接定位到目标的句柄。与JVM实现的内存布局相关,同一个符号引用在不同JVM实例上翻译出来的直接引用一般不会相同。如果有了直接引用,那所引用的目标必定存在于内存中。
第三步、初始化
这一步就正式开始执行类中定义的代码块,包括静态变量的赋值。到此,JVM类加载的整个过程就完成了。
最后,简要谈一下双亲委派模型,其目的是为了防止重复加载Java类型。
当前类加载器试图加载某个类时,会优先将当前任务抛给父加载器来完成,除非父加载器没找到相应的类型,最终才由该类加载器来完成该任务。
结语:我这里只是对JVM类加载机制进行了一个大概的总结,更详细的介绍可阅读周志明著的《深入理解Java虚拟机:JVM高级特性与最佳实践》一书。
继续阅读与本文标签相同的文章
-
300+道面试题&最全面试资料,你值得拥有! | Android面试宝典
2026-05-18栏目: 教程
-
小白学Python | 最简单的Django 简明教程
2026-05-18栏目: 教程
-
Jvm-Sandbox源码分析--模块刷新和卸载
2026-05-18栏目: 教程
-
MyCat数据库的基础配置及使用
2026-05-18栏目: 教程
-
阿里巴巴资深技术专家雷卷:值得开发者关注的 Java 8 后时代的语言特性
2026-05-18栏目: 教程
