JMV(一)类的加载机制

java文件的加载过程图


image.png

  1)Java文件先通过编译器变为.class文件
  2)类加载器将.class文件加载到JVM。
  类加载的过程简述:
  Java文件先通过编译器变为.class文件
  类加载器将.class文件加载到JVM。

一、JVM 组成和作用
1、 类装载器(Class Loader):.class文件由类加载器加载到数据运行区,
2、数据运行区 (Runtime data area):;
3、 执行引擎(Execution Engine):由于字节码只是JVM的指令集规范,不能交给底层操作系统执行,需要特定的命令解析器执行引擎翻译成底层系统指令,再交由CPU执行;
4、 本地库接口(Native Interface): 执行底层命令操作系统,需要调用其他语言的本地库接口来实现功能;

二、类装载的过程
  类从被加载到虚拟机内存中开始,到卸载出内存为止,它的整个生命周期包括:加载、验证、准备、解析、初始化、使用和卸载七个阶段。它们的顺序如下图所示


image.png

1、加载:根据查找路径找到相应class文件导入;
2、检查:检查加载的class文件正确性;
3、准备:给类中的静态变量分配内存空间;
  类变量(static)会分配内存,但是实例变量不会,实例变量主要随着对象的实例化一块分配到java堆中;
  这里的初始值指的是数据类型默认值,而不是代码中被显示赋予的值。比如
public static int value = 1; //在这里准备阶段过后的value值为0,而不是1。赋值为1的动作在初始化阶段。


image.png

注意,在上面value是被static所修饰的准备阶段之后是0,但是如果同时被final和static修饰准备阶段之后就是1了。我们可以理解为static final在编译器就将结果放入调用它的类的常量池中了。

4、解析:虚拟机将常量池中的符号引用替换成直接引用过程。符号引用理解为标示,而直接引用直接指向内存中的地址;
  解析阶段主要是虚拟机将常量池中的符号引用转化为直接引用的过程。什么是符号应用和直接引用呢?
  符号引用:以一组符号来描述所引用的目标,可以是任何形式的字面量,只要是能无歧义的定位到目标就好,就好比在班级中,老师可以用张三来代表你,也可以用你的学号来代表你,但无论任何方式这些都只是一个代号(符号),这个代号指向你(符号引用)
  直接引用:直接引用是可以指向目标的指针、相对偏移量或者是一个能直接或间接定位到目标的句柄。和虚拟机实现的内存有关,不同的虚拟机直接引用一般不同。
  解析动作主要针对类或接口、字段、类方法、接口方法、方法类型、方法句柄和调用点限定符7类符号引用进行。

5、 初始化:对静态变量和静态代码块执行初始化工作;
在这个阶段,java程序代码才开始真正执行
主要为类的静态变量赋予正确的初始值,JVM负责对类进行初始化,主要对类变量进行初始化。在Java中对类变量进行初始值设定有两种方式:
1)声明类变量是指定初始值
2)使用静态代码块为类变量指定初始值

VM初始化步骤
1、假如这个类还没有被加载和连接,则程序先加载并连接该类
2、假如该类的直接父类还没有被初始化,则先初始化其直接父类
3、假如类中有初始化语句,则系统依次执行这些初始化语句

类初始化时机:只有当对类的主动使用的时候才会导致类的初始化,类的主动使用包括以下六种:
1)创建类的实例,也就是new的方式
2)访问某个类或接口的静态变量,或者对该静态变量赋值
3)调用类的静态方法
4)反射(如 Class.forName(“com.shengsiyuan.Test”))
5)初始化某个类的子类,则其父类也会被初始化
6)Java虚拟机启动时被标明为启动类的类( JavaTest),直接使用 java.exe命令来运行某个主类

三、类加载器
1、三种类加载器
  Bootstrap ClassLoader :最顶层的加载类,主要加载核心类库,也就是我们环境变量下面%JRE_HOME%\lib下的rt.jar、resources.jar、charsets.jar和class等。另外需要注意的是可以通过启动jvm时指定-Xbootclasspath和路径来改变Bootstrap ClassLoader的加载目录。比如java -Xbootclasspath/a:path被指定的文件追加到默认的bootstrap路径中。我们可以打开我的电脑,在上面的目录下查看,看看这些jar包是不是存在于这个目录。
  Extention ClassLoader :扩展的类加载器,加载目录%JRE_HOME%\lib\ext目录下的jar包和class文件。还可以加载-D java.ext.dirs选项指定的目录。
  Appclass Loader:也称为SystemAppClass。 加载当前应用的classpath的所有类。

   这三种类加载器的加载顺序
Bootstrap ClassLoader > Extention ClassLoader > Appclass Loader

image.png

2、 类加载的三种方式
1) 通过命令行启动应用时,由JVM初始化加载含有main()方法的主类;
2) 通过Class.forName()方法动态加载,会默认执行初始化块,但Class.forName(name, initialize, loader)中的initialize可指定是否需要执行初始化块
3) 通过ClassLoader.loadClass() 方法动态加载;

3、 双亲委派原则
当一个类加载器收到类加载任务,会先交给其父类加载器去完成,因此最终加载任务都会传递到顶层的启动类加载器,只有当父类加载器无法完成加载任务时,才会尝试执行加载任务。
1)可以避免重复加载,父类已经加载了,子类就不需要再次加载
2)更加安全,很好的解决了各个类加载器的基础类的统一问题,如果不使用该种方式,那么用户可以随意定义类加载器来加载核心api,会带来相关隐患

参考:https://baijiahao.baidu.com/s?id=1636309817155065432&wfr=spider&for=pc

你可能感兴趣的:(JMV(一)类的加载机制)