JVM--类加载机制与类加载器

        我们都知道,我们写的java文件是不能直接运行的,当程序要主动使用某个类时,如果该类还没有还未被加载到内存中,则JVM会通过加载、连接、初始化3个步骤来对该类进行初始化class文件字节码文件加载与初始化,如果没有意外,这三个步骤会连续完成,生成一个代表这个类的java.lang.Class 对象,作为类的访问入口。
在这里插入图片描述

一、类加载

  1. 加载
            加载指的是将类的class文件读入到内存中,并且创建一个对应的java.lang.Class 对象。简单来说,当程序使用任何类时,都会先为之创建一个java.lang.Class 对象。
           类的加载是有类加载器来完成,类加载器通常是有JVM提供的,JVM提供的这些类加载器通常称为应用程序类加载器,也叫做系统类加载类。通过继承ClassLoader也可以创建自己的类加载器。
           加载的过程中主要做三件事:
           1 通过类的全限定名来获取此类的二进制字节流。
           2 将类的字节流代表的静态存储结构转为方法区(JDK7之前的版本)的运行时数据接口。
           3 创建对应的java.lang.Class 对象,作为访问方法区数据结构的入口。
  2. 连(链)接
           当类加载之后,将进入连接阶段,连接阶段主要分为三个阶段:
           A 验证:验证阶段用于检验被加载的类是否有正确的结构,并且和其他的类。确保class文件字节流包含的信息符合当前虚拟机的要求,能正确被虚拟机所识别。验证主要分为四个步骤:
                  文件格式验证:验证.class文件字节流是否符合class文件格式的规范,并且能被当前的虚拟机加载处理。如:主、次版本号,常量类型等
                  元数据验证:对字节码的信息进行语义验证。是否符合java语言的语法规范。
                  字节码验证:分析数据流和控制,验证语义合法,符合逻辑。主要针对方法体验证。—重要
                  符号引用验证:确认引用一定会被访问到。
                  —对整个验证阶段而言,这是一个重要但不必须的阶段。如果可以保证代码没有问题,那么可以关闭大部分的验证。毕竟验证也是需要花费时间的。
           B 准备:负责为类的静态变量分配内存,设置初始值。(这里的初始值是指数据类型的默认值,而不是代码中被赋予的值)。如下例子:
private static int a = 10;
/**
 * 过程  1:加载
 * 	   2:准备 :分配内存。a是static。此时a等于int的默认值0
 *     3:初始化:把a的真正值10赋值给a
 */

         C 解析:将符号引用转化为直接引用(即指向目标的指针)。
3. 初始化
         这是类加载机制的最后一步,在这个阶段,程序才算是真正开始执行。执行其静态初始化器和静态初始化成员变量。
4. 类加载器
         Bootstrap ClassLoader (启动类加载器):最顶层的类,主要加载核心类库,也就是我们环境变量下面%JRE_HOME%\lib下的rt.jar、resources.jar、charsets.jar和class等。
         Extention ClassLoader (扩展的类加载器):加载目录%JRE_HOME%\lib\ext目录下的jar包和class文件。
          Application ClassLoader (应用程序类加载器):也成为了system classLoader,加载当前应用的classpath的所有类。
5. 双亲委派机制
在这里插入图片描述
         双亲委派机制要求除了顶层的启动类加载器之外,其余的类加载器都应该有自己的父类加载器。
在这里插入图片描述 注:检查是自下往上,加载是自上往下
         从上面的结果可以看出,并没有获取到ExtClassLoader的父类,原因是Bootstrap Loader(启动类加载器)是用C语言实现的,找不到一个确定的返回父Loader的方式,于是就返回null。
         如果一个类收到了类加载的请求,它并不会自己先去加载,而是把这个请求委托给父类加载器去执行,如果父类加载器还存在父类加载器,则进一步向上委托,依次递归,请求最后到达顶层的启动类加载器,如果父类能够完成类的加载任务,就会成功返回,倘若父类加载器无法完成任务,子类加载器才会尝试自己去加载,这就是双亲委派模式。简单来说就是每个当儿子的收到任务时,都会先交给爸爸来做,当爸爸也做不了时,自己再来做。
         双亲委派机制的优势在于Java类随着它的类加载器一起具备一种带有优先级的层次关系,通过这种层级关系可以避免类的重复加载,当父亲已经加载了该类的时候,就没有必要子类加载器(ClassLoader)再加载一次。其次是考虑安全问题,Java的核心API不会被随意替换。假设接收到一个java.lang.Object的类,通过双亲委派机制一直传递到启动类加载器,而启动类加载器在Java 核心API中发现该类已经被加载,那么并不会加载接收到的java.lang.Object类,而是返回之前已经加载过的java.lang.Object类,这样就防止核心API被替换修改。(可以理解为接口模型,接口定义如果被修改了,那么已经实现的方法必然也不能使用。)

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值