Java的类加载和类加载器


下图来自网络,稍微展示一下Java的执行过程,就不专门自己画一个了(偷个懒),本篇主要入门级地介绍一下类加载和类加载器部分。整合一些自己的学习资料,做一个简单的记录,欢迎参考。
在这里插入图片描述


1. 类的生命周期

类从被加载到JVM开始,直到被卸载出内存,整个生命周期如图:
在这里插入图片描述

  1. 加载:查找并加载类文件的二进制数据(两个步骤:1.查找 2.加载)
    1)查找:通过类的全限定名(包结构加类名,这样才能唯一确定一个类)来获取该类的二进制字节流
    2)加载:a.把二进制字节流转化方法区的运行时数据结构 b.在堆上创建一个java.lang.Class对象,用来封装类在方法区内的数据结构,并向外提供方法区内数据结构的接口
  2. 连接:将已经读入内存的类的二进制数据合并到JVM运行时的环境中去,这样才能真正的被使用,其中又包含了如下几个步骤
    1)验证:确保被加载类的准确性,也就是检查.class文件是否符合JVM规范,其中又包括文件格式校验、元数据校验、字节码校验、符号引用校验
    2)准备:为类的静态变量分配内存,并初始化它们(这里是给默认值,比如int型的就赋值为0)
    3)解析:把常量池中的符号引用转换成直接引用(一般主要指的是类的常量池里的符号引用转换成字节引用)
  3. 初始化:为类的静态变量赋初始值,并执行类中的static代码块、构造函数(如果没有则会给添加默认的无参构造函数)等,初始化后的类就可以被使用了
  4. 使用:就是在运行时被使用
  5. 卸载:将类从JVM中移出

2. 加载类的方式

  • 最常见:从本地文件系统中加载、从jar等归档文件中加载
  • 动态加载的方式,就是将java源文件动态编译成class
  • 从网络下载、从专有数据库中加载等

3. 类加载器(Class Loader)

类加载器(Class Loader)负责将编译好的.class字节码文件加载到内存中,使得JVM可以实例化或以其他方式使用加载后的类。类加载器支持在运行时动态加载,这样可以节省内存空间。能灵活地从本地或者网络上加载类,可以通过命名空间的分隔来实现类的隔离,争强了整个系统的安全性等。

3.1 类加载器的分类

大体上其实分两种,一种是启动类加载器,一种是其他所有的类加载器。什么启动类加载器这么特殊呢?因为启动类加载器这个东西是由C++语言实现的,本身也是虚拟机的一部分。其他的加载器都是由Java语言编写,独立于虚拟机外部的,全都是继承至抽象类java.lang.ClassLoader。

JDK8:JVM自带的加载器分为如下的三种:

  • 启动类加载器(BootStrap Class Loader):启动类加载器是最底层的加载器,是由C++语言实现的。负责加载了JDK中的rt.jar文件中所有的Java字节码文件(rt.jar这个文件位于JDK的jre目录下,这是Java的基础类库,这样的核心字节码文件一般都是启动类加载的)
  • 扩展类加载器(Extension Class Loader):它负责将一些扩展功能的jar包加载到内存中,一般是加载“/lib/ext”目录的字节码文件
  • 系统类加载器(System Class Loader):通常程序员自己写的Java程序就是被这个类加载器加载的

注意:这个类加载器的分类是Java8版本的,在之后的新版本中,扩展类加载器(Extension Class Loader)被平台类加载器(Platform Class Loader)代替,而系统类加载器(System Class Loader)被应用程序类加载器(App Class Loader)代替。
扩展类加载器这种直接把需要的jar包放在ext文件夹下的方式,是并不安全的,在Java9中加入模块化的开发,于是就被模块化带来的这种天然的扩展能力给取代了。

除了Java自带的加载器以外,用户也可以自己定义加载器,一般都是是java.lang.ClassLoader的子类,我们可以自己定义类的加载方式,但是自定义的类加载器的加载都发生在所有系统类加载的后面的。

再加一些说明:

  • Java程序不能直接应用启动类加载器,直接设置ClassLoader为null就是默认地使用启动类加载器
  • 类加载不一定是马上要用到它了才去加载,JVM规范允许类加载器预料到某个类将要被使用的时候就预先去加载好
  • 如果在加载的时候class文件缺失,不会立即报错,而是在使用到它的时候才包LinkageError的错误,一直不用到它的话,就一直不报错。这种情况一般出现在用网络下载某些包的时候,可能因为网络的问题,导致类文件的缺失

3.2 类加载器的关系

我这里针对的是Java13版本
我们所有的自定义类加载器的父级都是应用程序类加载器(App Class Loader),而应用程序类加载器的父级一定是平台类加载器(Platform Class Loader),而平台类加载器的父级一定都是启动类加载器(Bootstrap Class Loader)。

这样的层次关系也就被称为——双亲委派模型

工作过程就是:如果一个类加载器收到类加载请求,它首先不会自己去加载这个类,而是把这个请求委派给父类加载器去完成,每个层次都是这样,当父加载器反馈自己无法完成这个加载请求时(它的搜索范围里没有这个类),子加载器才会自己去尝试完成加载。

这个双亲委派模型对Java程序的稳定运行十分重要,如果没有这样的层次关系,Java程序会非常混乱,比如,你写一个与rt.jar的类库中重名的类,会发现它可以正常编译,但是无法被加载运行。
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值