JVM—类加载器

类加载

1.类加载的过程

在这里插入图片描述
1.loading(加载)
  加载指的是将硬盘上的class文件,通过IO方式读取到内存中。
 通过使用不同的类加载器,可以从不同来源加载类的二进制数据,通常有如下几种来源:

  • 从本地文件系统加载class文件。
  • 从JAR包加载class文件,例如:JDBC的数据库驱动类就放在JAR文件中,JVM可以从JAR文件中直接加载该class文件
  • 通过网络加载class文件。
  • 把一个Java源文件动态编译,并执行加载。

类加载器通常无须等到“首次使用”该类时才加载类,Java虚拟机规范允许系统预先加载某些类。

2.linking(连接)
连接过程分为三部分:verification(校验)、preparation(准备)、resolution(解析)
  1)校验
    验证阶段用于校验被加载的类是否有正确的内部结构,并和其他类协调一致、Java是相对于C++语言是安全的语言,例如它有C++不具有的数组越界的检查。这本身就是对自身安全的一种保护。验证阶段是Java非常重要的一个阶段,它会直接的保证应用是否被恶意入侵的一道重要的防线,越是严谨的验证机制越安全。验证的目的在于确保Class文件的字节流中包含信息符合当前虚拟机要求,不会危害虚拟机自身安全。其主要包括四中验证,文件格式验证,元数据验证,字节码验证,符号引用验证。
文件格式验证:
    主要验证字节流是否符合Class文件格式规范,并且能被当前的虚拟机记载处理。例如:主,次版本号是否在当前虚拟机处理的范围之内。常量池中是否有不被支持的常量类型。指向常量的中的索引值是否存在不存在的常量或不符合类型的常量。
元数据验证:
    对字节码描述的信息进行语义的分析,分析是否符合java的语言语法的规范。
字节码验证:
    最重要的验证环境,分析数据和控制,确定语义是合法的,符合逻辑的。主要的针对元数据验证后对方法体的验证。保证类方法在运行时不会有危害出现。
符号引用验证:
    最重要的验证环境,分析数据和控制,确定语义是合法的,符合逻辑的。主要的针对元数据验证后对方法体的验证。保证类方法在运行时不会有危害出现。
  2)准备
    类准备阶段负载为类的静态变量分配内存,并设置默认初始值。
  3)解析
    将类的二进制数据中的符号引用替换成直接引用。说明一下:符号引用是一组符号来描述所引用的目标,符号可以是任何的字面形式的字面量,只要不会出现冲突能够定位到就行。布局和内存无关。直接引用:是指向目标的指针,偏移量或者能够直接定位的句柄。该引用是和内存的布局有关的,并且一定加载进行的。
3.initializing(初始化)
    初始化是为类的平台变量赋予正确的初始值,准备阶段和初始化阶段看似有点矛盾,其实是不矛盾,如果类中有语句:private static int a = 10,它的执行过程是这样的,首先字节码文件被加载到内存后,先进行连接的验证这一步骤,验证通过后准备阶段,给a分配内存,因为变量a是static,所以此时a等于int类型的默认初始值0,即a=0,然后到解析。到初始化这一步骤时,才把a的真正的值10赋给a,此时a=10。

2.类加载的时机

因为JVM是懒加载,并不会在启动的时候把所有的类都加载。那类何时才会被加载?

  1. 创建类的实例,也就是new一个对象
  2. 访问某个类或接口的静态变量,或者对该类变量赋值
  3. 调用类的静态方法
  4. 反射(Class.forName(“cn.zl.test”)或者String.class.getClassLoader().loadClass(“cn.zl.ByteCode1”);)
  5. 初始化一个类的子类(首先初始化子类的父类)
  6. JVM启动时标明的启动类,即文件名和类名相同的那个类

ps: final类的静态变量,如果在编译的时候就可以确定值。java编译器会在编译时直接把这个变量出现的地方替换成它的值。因此即使程序在使用该静态变量,也不会导致该类的初始化。反之,如果final类的静态Filed的值不能再编译时确定下来,则必须等到运行时才可以确定该变量的值,如果通过该类来访问它的静态变量,则会导致该了初始化。

3.类加载器种类

类加载器,大致分为四种:Bootstrap,extensions,app,自定义。

  1. (Bootstrap class loader): 它是用来加载java的核心类。由C++代码实现。例如:rt.jar。获取后打印对象为null。
    在这里插入图片描述

  2. (extensions class loader):扩展类加载器,它负载JRE的扩展目录。由java语言实现。父类加载器为Bootstrap。
    在这里插入图片描述

  3. (app class loader):应用类加载器,它负责加载classpath下的类文件。父加载器是extensions。
    在这里插入图片描述

  4. (custom class loader) 自定义加载器,既然是自定义,那负载加载我们自己指定路径下的类文件。父加载器是app。

4.类加载器的范围

四种类加载器的范围,肯定是不一样的。我们从Launcher这个类可以找到不同类加载的路径。
在这里插入图片描述
根据代码我们可以知道,bootstrap类加载器的路径是从System.getProperty(“sun.boot.class.path”);获取的。ext类加载器的路径是从System.getProperty(“java.ext.dirs”);获取的。app类加载器的路径是从System.getProperty(“java.class.path”);获取的。

  1. (Bootstrap class loader):加载的范围:…/jre/lib 和 …/jre/class。两个路径下。
    System.getProperty("sun.boot.class.path")
  2. (extensions class loader):加载范围:针对jre来说,是ext目录下。针对操作系统来说,每个操作系统都不一样,所以多出来的目录肯定是不一样的。
    在这里插入图片描述
  3. (app class loader):加载范围:主要是加载我们程序的classpath。
    在这里插入图片描述
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值