一、前言
本文主要讲解关于简述一下JVM加载class文件的原理,这也是在面试中,如果涉及到JVM相关的面试必问的环节。可以围绕,Java类文件编译之后的class文件,类加载器,列加载过程,和双亲委派进行回答,接下来分别讲解一下。
二、Java字节码class文件
class文件也就是也就是java文件编译之后生成的可执行文件,可以用javac 命令进行生成
直接只用记事本打开class文件是乱码的,这可以推荐一个插件,在IDEA安装BinEd这个插件就看class文件的字节码了
安装完成之后,在File->Open as Binary 就可以打卡class文件了。
可以看到Class文件开头的四个字节的无符号整数称为魔数(MagicNumber)。
魔数是Class文件的标识。值是固定的,为0xCAFEBABE(下插曲:为什么java是个咖啡☕,也是这个原因)
如果一个Class文件的头四个字节不是0XCAFEBABE,虚拟机在进行文件校验的时候会报错。使用魔数而不是扩展名来识别Class文件,主要是基于安全方面的考虑,因为文件扩展名可以随意更改。比如把MP4文件后缀改成class后缀。
三、类加载器
类加载器分为四种:前三种为虚拟机自带的加载器
启动类加载器(Bootstrap) C
负责加载SJAVA_HOME中jre/lib/rt,jar里所有的class,由C 实现,不是ClassLoader子类也叫系统类加载器,负责加载classpath中指定的iar包及目录中class
扩展类加载器(Extension)Java
负责加载iava平台中扩展功能的一些iar包,包括S]AVA HOME中ire/lib/jar或-Diavaext.dirs指定目录下的iar包
应用程序类加载器(AppClassLoader) Java
用户自定义加载器:Java.lang.ClassLoader的子类,用户可以定制类的加载方式
工作过程
1、当AppClassLoader加载一个class时,它首先不会自己去尝试加载这类,而是把类加载请求委派给父类加载器ExtClassLoader去完成。
2、当ExtClassLoader加载一个class时,它首先也不会自己去尝试加载这个类,而是把类加载请求委派给BootStrapClassLoader去完成。
3、如果BootStrapClassLoader加载失败(例如在$JAVA_HOME/jre/lib未查找到该class),会使用ExtClassLoader来尝试加载
4、若ExtClassLoader也加载失败,则会使用AppClassLoader来加载
5、如果AppClassLoader也加载失败,则会报出异常ClassNotFoundEx(eption
这其实这就是所谓的双亲委派模型
简单来说:如果一个类加载器收到了类加载的请求,它首先不会自己去尝试加载这个类,而是把请求委托给父加载器去完成,依次向上。
好处:防止内存中出现多份同样的字节码(安全性角度)器最终得到的都是同样一个 object对象,防止篡改JDK代码
四、类加载过程
JVM(Java虚拟机)加载class文件的原理主要包括以下几个步骤:
- 加载(Loading):当Java程序启动时,JVM会通过类加载器(ClassLoader)来加载需要执行的主类。类加载器会根据类的全限定名(包括包名和类名)查找对应的class文件,并将其字节码数据加载到内存中。
- 验证(Verification):在加载完class文件后,JVM会对字节码数据进行验证,确保其符合Java虚拟机规范,没有安全问题。验证主要包括文件格式验证、元数据验证和字节码验证。
- 准备(Preparation):在验证通过后,JVM会为类的静态变量分配内存空间,并给定默认初始值(0或null)。这一步操作主要是为类的静态变量预留空间,防止后续使用时出现内存溢出。
- 解析(Resolution):解析阶段主要是将类、接口、字段和方法的符号引用转化为直接引用。直接引用指向目标对象在内存中的具体位置,而符号引用只是一个符号性的标识。解析过程可能涉及到对其他类的加载和解析,这个过程可能是动态进行的。
- 初始化(Initialization):初始化阶段主要是执行类构造器<clinit>()方法。该方法主要负责初始化类的静态变量和执行静态初始化块。在<clinit>方法执行之前,类的静态变量已经被赋予了默认初始值。
通过以上五个阶段,JVM完成了对class文件的加载和初始化。
总结
Java代码在编译后首先会变成Java字节码(class文件),字节码被类加载器加载到JVM里,JVM执行字节码,最终需要转化为汇编指令在CPU上执行,Java中所使用的并发机制依赖于JVM的实现和CPU的指令,具体流程如下:
加载:Java类编译之后生成class文件,JVM会将class文件加载到内存中,生成这个类的一个Class对象
链接:将java类的二进制代码合并带JRE中,加载到类加载器,验证类信息是否符合JVM规范,有没安全问题;解析类变量(static)、常量赋予初始值,所以这些都不是在初始化时生成的
初始化:执行类构造器方法,如果发现父类没有初始化,会先去初始化父类
我正在参与2024腾讯技术创作特训营第五期有奖征文,快来和我瓜分大奖!