(二)JVM的类加载机制

前言

我们都知道Java是跨平台的,是因为不同平台下的JVM能将字节码文件解释为本地机器指令,JVM是怎么加载字节码文件的?答案就是ClassLoader。

今天我们仔细的来看看"类加载"这个过程,看看JVM的类加载机制到底是怎么样的?

什么情况下会加载类

什么情况下会加载类?这个是我们首先要了解的问题,才能更清楚的了解类加载机制。

1.运行一个主类的”main“方法时,会开启一个JVM进程之后,把主类加载到内存,然后开始执行你的main方法。

2.执行代码过程中,你使用到了某一个类,就会将对应的类加载到JVM内存中来。

初步了解类加载到使用的过程

加载 --》验证 --》 准备 --》 解析 --》 初始化 --》 使用 --》卸载,一般分为这几个阶段。

验证:把”.class"文件加载到内存后,必须先验证一下,校验它必须完全符合JVM规范,后续才能交给JVM来运行

准备:给类分配一定的内存空间,给类变量也分配内存空间并给它一个默认的初始值

解析:把符号引用替换为直接引用。

初始化:执行类初始化代码

初始化的详细说明

如上图,在准备阶段,只会给heartBeatInternal这个类变量一个默认的初始值,而这段赋值代码会在我们的初始化阶段来执行。

上图中的static代码块,也会在初始化阶段来执行。

我们还有一个很重要的问题需要考虑,什么时候会初始化一个类?

1.new一个实例对象的时候,就会触发这个类的加载到初始化的全过程。

2.执行main方法的类,也必须加载的时候立马初始化的

3.最重要的一点,如果初始化一个类的时候,发现它的父类还没初始化,那么就必须先初始化它的父类

类加载器

Java有哪些类加载器?

1.启动类加载器(Bootstrap ClassLoader)

JVM一启动,首先会依托启动类加载器,去加载Java安装目录下的lib目录中的核心类库

2.扩展类加载器(Extension ClassLoader)

负责加载Java安装目录下的lib/ext目录中的核心类库

3.应用类加载器(Application ClassLoader)

负责加载”classpath“环境变量所指定的路径的类,也就是我们写好的Java代码

4.自定义加载器

可以根据自己的需求去加载你的类

定义自已的类加载器分为两步:

          a、继承java.lang.ClassLoader

          b、重写父类的findClass方法

为什么偏偏只重写findClass方法?

      因为JDK已经在loadClass方法中帮我们实现了ClassLoader搜索类的算法,当在loadClass方法中搜索不到类时,loadClass方法就会调用findClass方法来搜索类,所以我们只需重写该方法即可。如没有特殊的要求,一般不建议重写loadClass搜索类的算法。

为什么要编写自己的类加载器?

        a.当class文件不在ClassPath路径下,默认系统类加载器无法找到该class文件,在这种情况下我们需要实现一个自定义的ClassLoader来加载特定路径下的class文件生成class对象。

        b.当一个class文件是在编译时加密或者混淆过的,在类加载的时候,对加密的类,考虑采用自定义的类加载器来解密文件即可,这样可以保证你的源代码不被人窃取

        c.JVM不支持热部署,那么要实现热部署,就必须自定义ClassLoader,原理是对比class文件的修改时间,如果class是被修改过了,那么就用ClassLoader把新的class文件重新加载到内存中。

双亲委派机制

JVM的类加载器是由父子层级结构的。如下图。

基于这个父子层级结构,就有一个双亲委派机制,即先找父亲去加载,不行的话再由儿子来加载。这样可以优效避免多层级的加载器结构重复加载某些类。

详细说明下,你的应该程序类加载器需要加载一个类,它首先会委派给自己的父类加载器去加载,最终会传到到顶层的类加载器去加载。但是父类加载器再自己负责的范围内没有找到这个类,那么就会下推加载权力给自己的子类加载器。

如果在你项目中建一个java.lang.String的类,那系统中用的String类是你定义的String类,还是原生api中的String类?

用双亲加载来解释就很容易理解用的是原生api中的String类。

JVM判断2个类是否相同的条件是:(1)全限定名相同(2)由同一个类加载器加载

总而言之,双亲委派模型有效解决了以下问题:

  • 每一个类都只会被加载一次,避免了重复加载,当父亲已经加载了该类时,就没有必要子ClassLoader再加载一次。
  • 有效避免了某些恶意类的加载(比如自定义了Java.lang.Object类,一般而言在双亲委派模型下会加载系统的Object类而不是自定义的Object类)

tomcat的类加载器

作为一个tomcat容器,既要解决跨应用公共共享问题也要解决独立应用独立问题。

在Tomcat中提供了一个Common ClassLoader,它主要负责加载Tomcat使用的类和Jar包以及应用通用的一些类和Jar包,例如CATALINA_HOME/lib目录下的所有类和Jar包。Tomcat会为每个部署的应用创建一个唯一的类加载器,也就是WebApp ClassLoader,它负责加载该应用的WEB-INF/lib目录下的Jar文件以及WEB-INF/classes目录下的Class文件。由于每个应用都有自己的WebApp ClassLoader,这样就可以使不同的Web应用之间相互隔离,彼此之间看不到对方使用的类文件。因此即使不同项目下的类全限定名有可能相等,也能正常工作。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值