类加载器和类的加载过程

1 类加载器

1.1 概述

  • 类加载器从文件系统或者网络中等途径加载class文件。
  • 类加载器只负责classs文件的加载,至于它是否可以运行由执行引擎(Execution Engine)决定。
  • 加载的类信息存放在方法区,除了类的信息之外,方法区还会存放运行时常量池(Run-Time Constant Pool)、字符串字面量和数字常量,而这些信息的来源是class中常量池(Constant Pool)的映射。

2 类的加载过程

在JVM中,类的加载过程分类三个阶段:

  • 加载阶Loading。
  • 链接 Linking。
  • 初始化 Initialization。

2.1 加载

  • 通过类的全限定名获取定义类的二进制字节流。

  • 将这个字节流的静态存储结构转化为方法区的运行时数据结构。

  • 在内存中生成一个代表该类的对象,作为方法区这个类的各种数据的访问入口。
    加载的途径:

  • 从本地文件系统加载

  • 通过网络获取,例如:Web Applet。

  • 从zip压缩包获取,成为以后jar和wer格式的基础。

  • 运行时计算生成,例如:动态代理技术。

  • 由其它文件生成,例如:JSP应用。

  • 从专有数据库获取class文件,很罕见。

  • 从加密文件中获取,防止class文件被反编译的保护措施。

2.2 链接

类的链接分为三个步骤:

2.2.1 验证 Verify

  • 确保class文件的字节流中包含的信息符合当前虚拟机的要求,保证被加载的类正确性,不会危害虚拟机安全。
  • 主要包括四种验证:文件格式验证、元数据验证、字节码验证和引用符号验证

2.2.2 准备 Prepare

  • 类变量分配内存并且设置初始值,即零值而不是赋值。
  • 不包含final修饰的static,因为final在编译的时候就分配好了,准备阶段会显示初始化。
  • 实例变量不会被在准备阶段初始化,类变量会分配在方法区,而实例变量会随着对象一起分配到堆中。

2.2.3 解析 Resolve

  • 将常量池内的符号引用转为直接引用
    什么是符号引用和直接引用
    符号引用:符号引用是以一组符号来描述所引用的目标,符号可以使任何形式的字面量,只要使用时能无歧义的定位到目标即可。
    直接引用:直接引用可以使直接指向目标的指针、相对偏移量或者是一个能简介定位到目标的句柄。

2.3 初始化

  • 除了加载阶段用户可以通过自定义加载器参与之外,其余步骤都是由虚拟机主导和控制的。
  • 执行类构造器方法()的过程,此构造器不同于父类构造器,若类有父类,则JVM会先执行父类的()

3 类加载器分类

JVM支持两种类型类加载器

  • 引导类加载器 Bootstrap ClassLoader
  • 自定义类加载器 User-Defined ClassLoader
    从概念上讲,自定义加载器一般由程序中开发人员自定义的类加载器,但是JVM是这样分类,将所有派生抽象类ClassLoader的类加载器都分化为自定义加载器。
    在这里插入图片描述
    图上的四种类加载器并不是包含和继承关系,而且所说的父类加载器或子类加载器只是指的这种包含关系,并不是面向对象的继承关系。

3.1 JVM自带的类加载器

3.1.1 启动类加载器 Bootstrap ClassLoader

也可称为引导类加载器

  • 这个类加载器使用的C/C++实现,嵌套在JVM内部。
  • 它是用来加载Java核心库(‘JAVA_HOME’/jre/lib/rt.jar、resouces.jar、sun.boot.class.path以及及-Xbootclasspath参数指定路径下的类库),用于提供JVM自身需要的类。
  • 不继承java.long.ClassLoader,没有父加载器。
  • 加载扩展类加载器和应用程序加载器,并指定为它们的父类加载器。
  • 出于安全,启动类加载器只加载包名为java、javax和sun等开头的类。

3.1.2 扩展类加载器 Extension ClassLoader

  • 有Java语言编写,由sun.misc.launcher$ExtClassLoader实现。
  • 派生于ClassLoader类。
  • 父类加载器为启动类加载器
  • java.ext.dirs系统变量所指定的目录或者从JDK安装路径下jre/lib/ext目录(扩展目录)下加载类库。如果用户创建的jar放在此路径也会由扩展类加载器加载。

3.1.3 应用程序类加载器 Application ClassLoader

  • Java语言编写,由sun.misc.launcher$AppClassLoader实现。
  • 派生于ClassLoader类。
  • 父类加载器为扩展类加载器
  • Classpath以及-classpath、-cp指定目录所指定的位置的类或者是jar文档,它也是Java程序默认的类加载器。
  • 该类加载器是程序中默认的类加载器,也就是说,一般的Java应用类都是用她来完成加载的。
  • 通过ClassLoader#getSystemClassLoader()可以获取到该类加载器。

3.2 用户自定义的类加载器

在开发中,类的加载器几乎是有上述三种类加载器互相配合执行的,在必要时,也可以自定义类的加载器来定制类的加载方式。
为什么要使用自定义类加载器?

  • 隔离加载类
  • 修改类的加载方式
  • 扩展加载资源
  • 防止源码泄露

4 双亲委派机制

JVM对class文件采用的是按需加载,也就是说,当这个类需要使用的时候该类才会被加载到内存生成class对象。并且在加载类的时候,JVM采用的是双亲委派机制,即把加载请求交给父类处理,这是一种任务委派模式。
在这里插入图片描述

4.1 工作原理:

  • 如果一个类加载器收到了类加载请求,如果有父类加载器,会把请求委托给父类加载器。
  • 如果父类加载器还存在父类加载器,则进一步向上委托,一次递归,直到顶层启动类加载器。
  • 如果父类加载器可以完成加载任务,则返回成功;若不够完成加载,返回失败,子加载器才会尝试去加载。

4.2 优势

  • 避免类重复加载。
  • 保护程序安全,防止篡改核心API。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值