类加载机制

java类从被加载到JVM到卸载出JVM,整个生命周期包括:加载(Loading)、验证(Verification)、准备(Preparation)、解析(Resolution)、初始化(Initialization)、使用(using)、和卸载(Unloading)七个阶段。其中验证、准备和解析三个部分统称为连接(Linking)。

1、加载

加载指的是将类的.class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后在堆区创建一个java.lang.Class对象,用来封装类在方法区内的数据结构。

类的加载通过JVM提供的类加载器完成,类加载器是程序运行的基础。程序在启动的时候,并不会一次性加载程序所要用到的所有class文件,而是根据需要,通过java的类加载器机制(classLoader)来动态加载某个class文件到内存中。

jvm在运行时会产生三个classLoader:

启动类加载器(BootStrap ClassLoader):是java类加载层次中最顶层的类加载器,负责加载jdk中的核心类库。由C++实现,不是classLoader的子类。

扩展类加载器(Extension ClassLoader):负责加载java的扩展类库,比如lib/ext或者java.ext.dirs系统属性指定的目录中的jar包。父类加载器为null。

系统类加载器(App ClassLoader):负责加载来自java命令的-classpath选项、java.class.path系统属性所指定的jar包和类路径。程序可以通过classLoader的静态方法getSystemClassLoader(),来获取系统类加载器。由java语言实现,父类加载器为ExtClassLoader。

除了java默认提供的这三个classLoader之外,用户可以根据需要定义自己的classLoader,这些自定义的classLoader都必须继承自java.lang.ClassLoader类。

通过使用不同的类加载器,可以从不同来源加载类的二进制数据。通常有如下几种情况:

从本地文件系统加载class文件,这是绝大部分实例程序的类加载方式。从jar包加载class类,这种方式也很常见。通过网络加载class类把一个java源文件动态编译,并执行加载,比如jsp。

2、连接

当类被加载之后,系统为之生成一个对应的class对象,接着进入连接阶段(验证-准备-解析),连接阶段负责把类的二进制数据合并到jre中。

验证:用于检测被加载的类是否有正确的内部结构,并和其他类协调一致。包括四种验证:文件格式验证、元数据验证、字节验证和符号引用验证。准备:负责为类变量分配内存,并设置默认初始值。解析:将类的二进制数据中的变量进行符号引用替换成直接引用。

3、初始化

在初始化阶段,主要为类的静态变量赋予正确的初始值。其实就是执行类构造器<clinit>()方法的过程。在java类中对类变量指定初始值有两种方式:a.声明类变量时指定初始值;b.使用静态初始化块为类变量指定初始值。

jvm初始化一个类包含如下步骤:

加载并连接该类先初始化其直接父类依次执行初始化语句当执行第2步时,系统对直接父类的初始化也遵循1~3,以此类推。

当一个类被主动引用后会触发初始化过程:

遇到new、getstatic、putstatic或invokestatic这4条字节码指令时,如果类没有进行过初始化,则需要先触发其初始化。生成这4条指令最常见的Java代码场景是:使用new关键字实例化对象时、读取或者设置一个类的静态字段(被final修饰、已在编译器把结果放入常量池的静态字段除外)时、以及调用一个类的静态方法的时候。使用java.lang.reflect包的方法对类进行反射调用的时候,如果类没有进行过初始化,则需要先触发其初始化。当初始化一个类的时候,如果发现其父类还没有进行过初始化,则需要触发父类的初始化。当虚拟机启动时,用户需要指定一个执行的主类(包含main()方法的类),虚拟机会先初始化这个类。当使用jdk7+的动态语言支持时,如果java.lang.invoke.MethodHandle实例最后的解析结果REF_getStatic、REF_putStatic、REF_invokeStatic的方法句柄,并且这个方法句柄所对应的类没有进行过初始化,则需要先触发器 初始化。当一个类如果是被动引用的话,不会触发初始化过程:

通过子类引用父类的静态字段,不会导致子类初始化。对于静态字段,只有直接定义该字段的类才会被初始化,因此当我们通过子类来引用父类中定义的静态字段时,只会触发父类的初始化,而不会触发子类的初始化。通过数组定义来引用类,不会触发此类的初始化。常量在编译阶段会存入调用类的常量池中,本质上没有直接引用到定义常量的类,因此不会触发定义常量的类的初始化。

4、使用

(略)

5、卸载

如果出现下面的情况,类就会被卸载:

该类所有的实例都已经被回收,也就是java堆中不存在该类的任何实例。加载该类的ClassLoader已经被回收。该类对应的java.lang.Class对象没有任何地方被引用,无法在任何地方通过反射访问该类的方法。如果以上三个条件全部满足,jvm就会在方法区垃圾回收的时候对类进行卸载,类的卸载过程其实就是在方法区中清空类信息,java类的整个生命周期就结束了。

类加载器

类加载器负责加载所有的类。其为所有被载入内存中的类生成一个java.lang.Class实例对象。一旦一个类被加载如JVM中,同一个类就不会被再次载入了。正如一个对象有一个唯一的标识一样,一个载入JVM的类也有一个唯一的标识。在Java中,一个类用其全限定类名(包括包名和类名)作为标识;但在JVM中,一个类用其全限定类名和其类加载器作为其唯一标识。例如,如果在pg的包中有一个名为Person的类,被类加载器ClassLoader的实例kl负责加载,则该Person类对应的Class对象在JVM中表示为(Person.pg.kl)。这意味着两个类加载器加载的同名类:(Person.pg.kl)和(Person.pg.kl2)是不同的、它们所加载的类也是完全不同、互不兼容的。

前面我们已经介绍了java中的几种类加载器,下面我们用一张图展示他们的层次关系:

类加载步骤

类加载器加载class大致需要如下8个步骤:

检测此Class是否载入过,即在缓冲区中是否有此Class,如果有直接进入第8步,否则进入第2步。如果没有父类加载器,则要么Parent是根类加载器,要么本身就是根类加载器,则跳到第4步,如果父类加载器存在,则进入第3步。请求使用父类加载器去载入目标类,如果载入成功则跳至第8步,否则接着执行第5步。请求使用根类加载器去载入目标类,如果载入成功则跳至第8步,否则跳至第7步。当前类加载器尝试寻找Class文件,如果找到则执行第6步,如果找不到则执行第7步。从文件中载入Class,成功后跳至第8步。抛出ClassNotFountException异常。返回对应的java.lang.Class对象。

类加载机制

全盘负责:当一个类加载器负责加载某个Class时,该Class所依赖和引用其他Class也将由该类加载器负责载入,除非显示使用另外一个类加载器来载入。双亲委派:先让父类加载器试图加载该Class,只有在父类加载器无法加载该类时才尝试从自己的类路径中加载该类。通俗的讲,就是某个特定的类加载器在接到加载类的请求时,首先将加载任务委托给父加载器,依次递归,如果父加载器可以完成类加载任务,就成功返回;只有父加载器无法完成此加载任务时,才自己去加载。缓存机制:保证所有加载过的Class都会被缓存,当程序中需要使用某个Class时,类加载器先从缓存区中搜寻该Class,只有当缓存区中不存在该Class对象时,系统才会读取该类对应的二进制数据,并将其转换成Class对象,存入缓冲区中。这就是为很么修改了Class后,必须重新启动JVM,程序所做的修改才会生效的原因。

自定义的类加载器

jvm除跟类加载器之外的所有类加载器都是ClassLoader子类的实例,开发者可以通过拓展ClassLoader的子类,并重写该ClassLoader所包含的方法实现自定义的类加载器。ClassLoader有如下两个关键方法:

loadClass(String name,boolean resolve):该方法为ClassLoader的入口点,根据指定名称来加载类,系统就是调用ClassLoader的该方法来获取指定类的class对象。findClass(String name):根据指定名称来查找类如果需要实现自定义的ClassLoader,则可以通过重写以上两个方法来实现,通常推荐重写findClass()方法而不是loadClass()方法。classLoader()方法的执行步骤:1)findLoadedClass():来检查是否加载类,如果加载直接返回;2)父类加载器上调用loadClass()方法。如果父类加载器为null,则使用跟类加载器加载;3)调用findClass(String)方法查找类。从这边可以看出,重写findClass()方法可以避免覆盖默认类加载器的父类委托,缓冲机制两种策略;如果重写loadClass()方法,则实现逻辑更为复杂。

java类加载机制、类加载器、自定义类加载器相关推荐

  1. Java虚拟机JVM学习06 自定义类加载器 父委托机制和命名空间的再讨论

    Java虚拟机JVM学习06 自定义类加载器 父委托机制和命名空间的再讨论 创建用户自定义的类加载器 要创建用户自定义的类加载器,只需要扩展java.lang.ClassLoader类,然后覆盖它的f ...

  2. 面试干货4——你对Java类加载器(自定义类加载器)有了解吗?

    类加载器 推荐:在准备面试的同学可以看看这个系列 一.类加载器的作用 二.Java虚拟机类加载器结构 1. 引导类(启动类)加载器 2. 扩展类加载器 3. 系统类加载器 三.类加载器的加载机制 1. ...

  3. 面试-JVM-类加载-类加载器--自定义类加载器-JVM调优

    文章目录 ==类加载== 谈谈你对类文件结构的理解?有哪些部分组成? 谈谈你对类加载机制的了解? 编写java代码是如何运行起来的? 类加载机制 类加载各阶段的作用分别是什么? 有哪些类加载器?分别有 ...

  4. 双亲委托类加载机制_图解JVM类加载机制和双亲委派模型

    我们都知道以 .java 结尾的 Java 源文件,经过编译之后会变成 .class 结尾的字节码文件.JVM 通过类加载器来加载字节码文件,然后再执行程序. 什么时候加载一个类 那么,什么时候类加载 ...

  5. 【Java类加载机制】深入加载器

    加载的全过程,分为三步:加载.链接(验证.准备.解析).初始化.(使用.卸载) 加载 字节码的来源: 硬盘上的class文件 网络上的字节码(服务器.其他程序发来的) jar包.zip文件 数据库中的 ...

  6. 【Java类加载机制】深入类加载器(二)自定义加密、解密类加载器

    类加载器原理 将class文件字节码内容加载到内存中,并将这些静态数据转换成方法区中的运行时数据结构,在堆中生成一个代表这个类的java.lang.Class对象,作为方法区类数据的访问入口. 类加载 ...

  7. 深入理解Java虚拟机——JVM类加载机制(类加载过程和类加载器)

    一.什么是类加载机制? 虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验.转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型,这就是虚拟机的类加载机制. 二.类加载的时机 类 ...

  8. 类加载机制、双亲委派机制深度解析以及如何自定义类加载器

    文章目录 1.类加载运行的全过程 2. JVM类加载器的初始化 3.双亲委派机制 4.编写自定义类加载器 5.(Tomcat)如何打破双亲委派机制 当我们运行一个类的时候,首先要通过类加载机制把类加载 ...

  9. JVM:类加载机制之类加载器

    JVM设计者把类加载阶段中的"通过'类全名'来获取定义此类的二进制字节流"这个动作放到Java虚拟机外部去实现,以便让应用程序自己决定如何去获取所需要的类.实现这个动作的代码模块称 ...

  10. 自定义类加载器以及打破双亲委派

    0x01 自定义类加载器 自定义类加载器加载一个类需要:继承ClassLoader,重写findClass,如果不想打破双亲委派模型,那么只需要重写findClass:如果想打破双亲委派模型,那么就重 ...

最新文章

  1. 测试工具–super-mack
  2. 【Android 内存优化】Bitmap 图像尺寸缩小 ( 设置 Options 参数 | inJustDecodeBounds | inSampleSize | 工具类实现 )
  3. 设置sonar 排除扫描文件及问题
  4. g++ linux intel 汇编,g++ linux
  5. Android中的设计模式之观察者模式
  6. matlab平行因子_基于MATLAB某客车悬置系统优化与运动仿真
  7. java学习笔记—标准连接池的实现(27)
  8. 速读-A3基于注意力机制的神经网络处理器
  9. Please select Android SDK的解决
  10. Eclipse 添加 JD-eclipse 反编译插件
  11. 微型计算机控制技术学科认识,微型计算机控制技术学习心得.docx
  12. 3dmax:3dmax三维VR渲染设置(V-Ray帧缓存、V-Ray全局开关、V-Ray图像采样器、自适应细分采样器、V-Ray环境、全局确定性蒙特卡、摄像机、颜色贴图)之详细攻略(切记收藏!)
  13. qq手机助手连接服务器失败是什么原因,按键精灵手机助手教程,按键精灵手机助手连不上手机解决方法...
  14. 集成混合运动与大功率柔性操作的半人马救灾机器人(4)——项目成果展示
  15. nginx防恶意刷新
  16. 中兴JAVA直板手机_中兴(zte)L880智能手机(黑色 双卡双待 直板按键 老人机) 京东199元...
  17. 侯捷C++学习记录-面向对象高级编程上
  18. Linux性能分析方法
  19. python turtle绘制柱状图_python画柱状图
  20. 如何处理印象笔记安装后图标不显示的情况

热门文章

  1. 宅急送 项目第八天 JBPM工作流框架
  2. pat乙级1087C语言
  3. 使用gluLookAt发生无法解析符号的错误
  4. Python+Flask
  5. 二、计算机网络体系架构——网络工程师成长之路
  6. 经纬度转小数格式 java_经纬度格式转换工具
  7. 一个定制CFileDialog对话框的实例
  8. 数据库性能测试-mysql篇
  9. Windows端口开启关闭
  10. RANSAC算法(仅供学习使用)