VM 加载class文件的原理是什么?

2021-04-28 20:03发布

6条回答
路小雨xiaoyu
2021-06-03 17:05

一、原理机制

  虚拟机(jvm)把描述类的数据从Class文件加载到内存,并对数据进行校验,解析和初始化,最终形成可以被虚拟机直接使用的java类型。

  java中的所有类,都需要有由类加载器装载到JVM中才能运行。类加载器本身也是一个类,而它的工作就是把Class文件从硬盘读取到内存中。在写程序的时候,我们几乎不需要关心类的加载,因为这些都是隐式装载的,除非我们有特殊的用法,像是反射,就需要显示的加载所需要的类。

类装载的方式,有两种:

1、隐式装载,程序在运行过程中当碰到通过new等方式生成对象时,隐式调用类装载器对应的类到jvm中

2、显示装载,通过class.forname()等方式,显示加载需要的类

  java类的加载是动态的,它并不会一次性将所有类全部加载后再运行,而是保存程序运行的基础类(像是基类)完全加载到JVM中,至于其他类,则在需要的时候才才加载。这当然就是为了节省内存开销

二、类加载器

  JVM中类的加载是由有类加载器(ClassLoader)和它的子类来实现的,Java中的类加载器是一个重要的Java运行时系统组件,他负责在运行时查找和装入类文件中的类。

2.1、什么是类加载器,类加载器有哪些

  实现通过类的全限定名获取该类的二进制字节流的代码块叫做类加载器,它把类的.class文件的数据读入到内存中,通常是创建一个字节数组读入.class文件,然后产生与所加载类对应的class对象,加载完成后,Class对象还不完整,所以此时的类还不可用。

  主要有以下四种类加载器:

  1、启动类加载器(Bootstrap ClassLoader)用来加载java核心类库,无法被java程序直接引用。

  2、扩展类加载器(Extensions ClassLoader)用来加载java的扩展库。java虚拟机的实现会提供一个扩展库目录。该类加载器在此目录里面查找并加载java类,它的父类加载器是Bootrap。

  3、系统类加载器(System ClassLoader)根据java应用的类路径(CLASSPATH)来加载java类。一般来说,java应用的类都是由它来完成加载的。可以通过ClassLoader.getSystemLoader()来获取它,它是应用最广泛的类加载器。。

  4、用户自定义类加载器,通过继承java.lang.ClassLoader类的方式实现。

2.2类装载的执行过程

类装载分为以下5个步骤:

  • 加载:根据查找路径找到相应的class问价然后导入;

  • 验证:检查加载的class文件的正确性;

  • 准备:给类中的静态标量分配内存空间;

  • 解析:虚拟机将常量池中的符号引用替换成直接引用的过程。符号引用就理解为一个标示,而在直接引用直接指向内存中的地址;

  • 初始化:对静态变量和静态代码块进行初始化工作;

三、双亲委派模型

  在介绍双亲委派模型之前回顾一下类加载器。对于任意一个类,都需要由加载它的类加载器和这个类本身一同确立在JVM中的唯一性,每个类加载器,都有一个独立的类名称空间。类加载器就是根据全限定名将class文件加载到JVM中,然后再转化为class对象。

 

 

 类加载器分类:

  • 启动类加载器(Bootstrap ClassLoader),是虚拟机自身的一部分,用来加载Java_HOME/lib目录中的,或者被-Xbootclasspath参数所指定的路径中并且被虚拟机识别的类库;

  • 扩展类加载器(Extension ClassLoader),负责加载\lib\ext目录或Java.ext.dirs系统变量所指定的路径中的所有类库;

  • 应用程序类加载器(Application ClassLoader),负责加载用户类路径(classpath)上的指定类库,我们可以直接使用这个类加载器。一般情况下,我们没有自定义类加载器,默认就是用这个加载器。

  从Java 2(JDK 1.2)开始,类加载过程采取了父亲委派机制(PDM)。PDM更好的保证了Java平台的安全性,在该机制中,JVM自带的Bootrap是根加载器,其他的加载器都有且仅有一个父类加载器。

  双亲委派模型:如果一个类加载器收到了类加载的请求,他首先不会自己去加载这个类,而是把这个请求委派给父类加载器去完成,每一层的类加载器都是如此,这样所有的加载请求都会被传送到顶层的启动类加载器中,只有当父类加载器无法完成加载请求(它的搜素范围中没找到所需的类)时,子加载器才会尝试去加载类。

  采用双亲委派的一个好处是比如加载位于rt.jar包中的类java.lang.Object,不管是哪个加载器加载这个类,最终都是委托给顶层进行加载,这样就保证了使用不同的类加载器最终得到的都是一个Object对象。

  简述双亲委派:当一个类收到了类加载请求时,不会自己先去加载这个类,而是将其委派给父类,如果此时父类不能加载,反馈给子类,由子类去完成类的加载。

一周热门 更多>