JVM的类加载机制:在代码编译后,就会生成JVM(Java虚拟机)能够识别的二进制字节流文件(*.class)。而JVM把Class文件中的类描述数据从文件加载到内存,并对数据进行校验、转换解析、初始化,使这些数据最终成为可以被JVM直接使用的Java类型。

类的生命周期包括:加载、链接、初始化、使用和卸载,其中加载、链接、初始化,属于类加载的过程,我们下面仔细讲解。使用是指我们new对象进行使用,卸载指对象被垃圾回收掉了。

一、Loading加载

通过类的全限定名(包名 + 类名),获取到该类的.class文件的二进制字节流将二进制字节流所代表的静态存储结构,转化为方法区运行时的数据结构。在内存中生成一个代表该类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口。
加载二进制数据到内存 —> 映射成jvm能识别的结构 —> 在内存中生成class文件

二、Linking链接

链接是指将上面创建好的class类合并至Java虚拟机中,使之能够执行的过程,可分为验证、准备、解析三个阶段。

1、验证(Verify)

确保class文件中的字节流包含的信息,符合当前虚拟机的要求,保证这个被加载的class类的正确性,不会危害到虚拟机的安全。

2、准备(Prepare)

为类中的静态字段分配内存,并设置默认的初始值,比如int类型初始值是0。被final修饰的static字段不会设置,因为final在编译的时候就分配

3、解析(Resolve)

解析阶段的目的,是将常量池内的符号引用转换为直接引用的过程(将常量池内的符号引用解析成为实际引用)。如果符号引用指向一个未被加载的类,或者未被加载类的字段或方法,那么解析将触发这个类的加载(但未必触发这个类的链接以及初始化。)
事实上,解析器操作往往会伴随着 JVM 在执行完初始化之后再执行。 符号引用就是一组符号来描述所引用的目标。符号引用的字面量形式明确定义在《Java 虚拟机规范》的Class文件格式中。直接引用就是直接指向目标的指针、相对偏移量或一个间接定位到目标的句柄。

解析动作主要针对类、接口、字段、类方法、接口方法、方法类型等。对应常量池中的 CONSTANT_Class_info、CONSTANT_Fieldref_info、CONSTANT_Methodref_info等。

三、initialization初始化

初始化就是执行类的构造器方法init()的过程。
这个方法不需要定义,是javac编译器自动收集类中所有类变量的赋值动作和静态代码块中的语句合并来的。

若该类具有父类,jvm会保证父类的init先执行,然后在执行子类的init。

类加载器的分类

一、启动类/引导类:Bootstrap ClassLoader

这个类加载器使用C/C++语言实现的,嵌套在JVM内部,java程序无法直接操作这个类。
它用来加载Java核心类库,如:JAVA_HOME/jre/lib/rt.jar、resources.jar、sun.boot.class.path路径下的包,用于提供jvm运行所需的包。

并不是继承自java.lang.ClassLoader,它没有父类加载器

它加载扩展类加载器应用程序类加载器,并成为他们的父类加载器

出于安全考虑,启动类只加载包名为:java、javax、sun开头的类。

二、扩展类加载器:Extension ClassLoader

Java语言编写,由sun.misc.Launcher$ExtClassLoader实现,我们可以用Java程序操作这个加载器
派生继承自java.lang.ClassLoader,父类加载器为启动类加载器

从系统属性:java.ext.dirs目录中加载类库,或者从JDK安装目录:jre/lib/ext目录下加载类库。我们就可以将我们自己的包放在以上目录下,就会自动加载进来了。

三、应用程序类加载器:Application Classloader

Java语言编写,由sun.misc.Launcher$AppClassLoader实现。
派生继承自java.lang.ClassLoader,父类加载器为启动类加载器

它负责加载环境变量classpath或者系统属性java.class.path指定路径下的类库

它是程序中默认的类加载器,我们Java程序中的类,都是由它加载完成的。

我们可以通过ClassLoader.getSystemClassLoader()获取并操作这个加载器

四、自定义加载器

一般情况下,以上3种加载器能满足我们日常的开发工作,不满足时,我们还可以自定义加载器
比如用网络加载Java类,为了保证传输中的安全性,采用了加密操作,那么以上3种加载器就无法加载这个类,这时候就需要自定义加载器。

1、自定义加载器实现步骤

继承java.lang.ClassLoader类,重写findClass()方法
如果没有太复杂的需求,可以直接继承URLClassLoader类,重写loadClass方法,具体可参考AppClassLoader和ExtClassLoader。

2、获取ClassLoader几种方式

它是一个抽象类,其后所有的类加载器继承自 ClassLoader(不包括启动类加载器)

// 方式一:获取当前类的 ClassLoader
clazz.getClassLoader()
// 方式二:获取当前线程上下文的 ClassLoader
Thread.currentThread().getContextClassLoader()
// 方式三:获取系统的 ClassLoader
ClassLoader.getSystemClassLoader()
// 方式四:获取调用者的 ClassLoader
DriverManager.getCallerClassLoader()

类加载机制—双亲委派机制

jvm对class文件采用的是按需加载的方式,当需要使用该类时,jvm才会将它的class文件加载到内存中产生class对象。

在加载类的时候,是采用的双亲委派机制,即把请求交给父类处理的一种任务委派模式。

1、工作原理

  1. 如果一个类加载器接收到了类加载的请求,它自己不会先去加载,会把这个请求委托给父类加载器去执行。

  2. 如果父类还存在父类加载器,则继续向上委托,一直委托到启动类加载器:Bootstrap ClassLoader。

  3. 如果父类加载器可以完成加载任务,就返回成功结果,如果父类加载失败,就由子类自己去尝试加载,如果子类加载失败就会抛出ClassNotFoundException异常,这就是双亲委派模式。

2、第三方包加载方式:反向委派机制

在Java应用中存在着很多服务提供者
(Service Provider Interface,SPI),这些接口允许第三方为它们提供实现,如常见的 SPI 有 JDBC、JNDI等,这些 SPI 的接口属于 Java 核心库,一般存在rt.jar包中,由Bootstrap类加载器加载。而Bootstrap类加载器无法直接加载SPI的实现类,同时由于双亲委派模式的存在,Bootstrap类加载器也无法反向委托AppClassLoader加载器SPI的实现类。在这种情况下,我们就需要一种特殊的类加载器来加载第三方的类库,而线程上下文类加载器(双亲委派模型的破坏者)就是很好的选择。

从图可知rt.jar核心包是有Bootstrap类加载器加载的,其内包含SPI核心接口类,由于SPI中的类经常需要调用外部实现类的方法,而jdbc.jar包含外部实现类(jdbc.jar存在于classpath路径)无法通过Bootstrap类加载器加载,因此只能委派线程上下文类加载器把jdbc.jar中的实现类加载到内存以便SPI相关类使用。显然这种线程上下文类加载器的加载方式破坏了“双亲委派模型”,它在执行过程中抛弃双亲委派加载链模式,使程序可以逆向使用类加载器,当然这也使得Java类加载器变得更加灵活。

3、沙箱安全机制

自定义 String 类,但是在加载自定义 String 类的时候会率先使用引导类加载器加载,而引导类加载器在加载的过程中会先加载 JDK 自带的文件(rt.jar 包中的 javalangString.class),报错信息说没有 main 方法就是因为加载的 rt.jar 包中的 String 类。这样可以保证对 Java 核心源代码的保护,这就是沙箱安全机制。

JVM 类加载机制与加载过程相关推荐

  1. 类加载器及其加载过程

    一.内存结构概述 内存结构简图: 内存结构详细图: 中文: 英文: 二.类加载器与加载过程 类加载器子系统作用 图解: 描述: 1.类加载器子系统负责从文件系统或者网络中加载class文件,class ...

  2. 类加载顺序及加载过程详解

    转自: 类加载顺序及加载过程详解 下文笔者讲述类的加载顺序及加载过程的详解说明,如下所示 java创建对象的方式分为以下四种 new 反射克隆反序列化 class对象获取的方式分享 //没有完成初始化 ...

  3. JVM学习02——内存加载过程(类加载器)

    类加载器 一.效果 class文件被load进内存,同时生成一个Class类的对象,可以用这个Class对象指向这块内容.(class类的对象不是new出来的,是hotspot中C++代码load出来 ...

  4. 从JVM看类的加载过程与对象实例化过程

    一. 类的加载过程 1. 类的加载过程大致是个什么过程? 我们编写产生.java文件,这些.java文件经过Java编译器编译成拓展名为.class的文件,.class文件中保存着Java代码经转换后 ...

  5. 欧尼酱讲JVM(02)——类的加载过程

    我们知道,在代码编译后,就会生成JVM(Java虚拟机)能够识别的二进制字节流文件(*.class).而JVM把Class文件中的类描述数据从文件加载到内存,并对数据进行校验.转换解析.初始化,使这些 ...

  6. JVM初学之类的加载过程

    类的加载过程分为三个步骤: 装载:(这个过程使用类加载器完成的) a)类加载器通过一个类的全限定名找到该java编译后的class文件,并转化为字节流. b)这些字节流中会有描述该类的静态存储结构的信 ...

  7. Java虚拟机(JVM)之类的加载过程详解

    java程序在对某个类进行引用.使用时,就会开始对该类进行加载,比如直接使用类加载器进行显式加载.创建该类的对象.使用该类的类变量等情况.类的加载是通过java虚拟机的类加载子系统完成的.类的加载主要 ...

  8. 【Android 热修复】热修复原理 ( 类加载机制 | PathClassLoader 加载 Dex 机制 | PathDexList 查找 Class 机制 | 类查找的顺序机制 )

    文章目录 一. PathClassLoader 加载 Dex 机制 二. PathDexList 查找 Class 机制 三. 类查找的顺序机制 一. PathClassLoader 加载 Dex 机 ...

  9. JVM 类加载机制:编译器常量与初始化

    1. 前言 最近在研究JVM虚拟机类加载机制的时候,我们了解到了类加载机制的生命周期以及在准备阶段,JVM虚拟机会对类的静态变量进行初始化,这个时候只是会将静态变量初始化为默认的初始值.对静态变量的定 ...

最新文章

  1. 我,某大学副教授+副处级,工资7300/月,老婆天天骂我窝囊废……
  2. python数据结构学习笔记(五)
  3. 分享预告:「数据安全问题」+「 股权与期权」
  4. 黑马lavarel教程---7、文件上传
  5. Linux-鸟菜-5-文件权限
  6. 如何创造char二叉树C语言,递归创建二叉树c语言实现+详细解释
  7. JS模式--职责链模式
  8. LeakCanary: 让内存泄露无所遁形
  9. 更多Java之行内容,需要看直播请关注微薄
  10. matlab 的cat函数
  11. iOS:通信录(完成)(18-01-18更)
  12. javaSE_base04_集合框架
  13. 一叶知秋:基于“单目标域样本”的领域自适应方法
  14. windows切屏快捷键
  15. 计算机rapter 流程图,Raptor设计程序流程图并运行的具体操作步骤
  16. Dynamics AX 2012 的工业物联网解决方案
  17. 如何看待社会的阴暗面
  18. java将小写金额转为大写金额
  19. USB CCID理解
  20. 鸢尾花python分类_鸢尾花分类——Python机器学习起步

热门文章

  1. 学习笔记第二节:最大权闭合图
  2. 提示用户输入用户名,然后再提示输入密码, 如果用户名是“admin”并且密码是“88888”,则提示正确, 否则,如果用户名不是admin则提示用户用户名不存在,
  3. c语言中assert函数是什么
  4. Linux 关于安装KDE桌面系统的坑
  5. 山西小镇喜现豪华“动物车队”可骑驴遛马坐牛赶驼
  6. JS对象的可枚举属性和不可枚举属性
  7. 【QT开发专题-天气预报】2. JSON 简介
  8. Java学习 第三章 Steam输入输出流
  9. ubuntu终端不显示绝对路径
  10. 戏说开源数据库“五虎将”