00:00
那接着啊,咱们来看一看中篇的第四章,在这呢,也是咱们这个中篇的最后一章,咱们呢,再带着大家呢来谈一谈叫类的加载器,咱们在这个第三章啊戴尔大家呢,主要讲的叫类的加载过程啊,或者我们也可以称为呢叫类的生命周期,那主要涉及到呢,就是咱们讲的这样的几个环节,那么在这几个环节中的第一个环节,咱们呢,称为叫loading阶段,那也把它呢也叫做类的加载阶段,对吧?这个类的加载跟咱们说的整个类的加载过程,这是两个概念,这呢叫广义上的这个呢,是其中的一个环节,这个大家要注意,那么这个类的加载这个loading环节呢,咱们说主要做这个事儿啊,咱们也说过了,对吧,就是呢使用类的加载器。然后将那我们这个嗯,类中的这个二进制数据呢,这个有可能来自于各种各样的这个方式,对吧,咱们这块也提到了,通常的话呢,我们说是从一个点class结尾的一个磁写码文件当中,把这个数据呢,以二进制流的方式呢,读入到我们这个方法区,方法区呢,我们就形成一个叫类模板数据,对吧?那同时的话呢,对应着一个大的class的一个实例。
01:07
啊,对应大的class的一个实例,那整个我们看到的相当于就是这样的一个场景。没有问题的,对吧,好,那我们说在这个阶段当中,咱们呢,使用到了叫类的加载器,注意类的加载器呢,只跟我们这个过程一打交道,跟后面的链接初始化没有任何关系。就是已经呢加载到内存中,我们在方法区生成了叫类的模板数据,那然后呢,在对空间中我们得到一个大的class的一个这个实例,对吧?这个实例呢,就指向了你方法驱动的这个类模板数据,这个场景做完之后,我们类的加载器要做的事呢,其实就结束了,那后续呢,就是啊后边我们GM呢要做这些事情,那么针对我们说的第一个环节当中类的加载器,那我们呢,在中篇当中再把它展开呢,带着大家呢再讲一讲。包括呢,我们在上面呢,其实也提到过双亲尾派模型,那至于说破坏双亲尾派机制的这个这个情况呢,我们没有讲对吧?那热替换的实现,包括沙箱安全机制,我们再给大家讲一讲,以及呢如何自定义类的加载器,那这块呢,我们都带着大家呢展开来说一说,以及呢像class的源码分析。
02:16
好,那我们下边呢,就展开来说,首先呢,我们来看一个这个概述。说类加载器呢,是障碍虚拟机执行类加载机制的一个前提,嗯,这呢就相当于我们得有第一个叫loading的环节啊,如果没有它的话呢,后续的这个都白白白白提,对吧?那这是第一个环节,必须要这个使用内的加载器进行一个加载的,那class load呢,是我们说Java的一个核心组件,所有的class,注意这里边提到了所有的class,不管呢,是系统给我们提供的叫核心API,包括呢,第三方包中的这个class文件,包括呢,我们自定义的这些类等等,呃,要想使用都必须使用class loader,把它们呢,加载到咱的内存当中。他负责呢,通过各种方式将class信息的二进制数据读入到GM内部,那各种方式呢,咱们在第三章当中,那是不是这块也都提到了,对吧,那好多种这个获取的方式。
03:10
好,那接着呢,它会生成一个大的class的一个实例,交给虚拟机进行链接和初始化,那刚才也提到了,说classo呢,只负载,只负责这个加载的loading阶段,后续的这个链接初始化啊,他这个他不管啊,包括呢,它是否能够正常的运行,执行这个呢,由我们这个执行引擎来决定,那执行引擎里边呢,我们也会记录相应的这个指令,它的一个偏移量,对吧?啊依次呢去执行这呢都是后续GM的这个结构去完成的,那咱们在这个第三章当中其实也提到过类似的这样一张图,那我们是在这个卸载的时候呢,给大家提到的,对吧,这里边儿涉及到的一些相关的指针的情况,那我们在这个角度呢,再来看一看。咱们说呢,这个得到的这个类模板数据,它呢,跟咱们的类的加载器它之间呢,是相互的一个引用关系,那class so呢,它也记录了一个什么呀,我们叫呃加载的这类的一个集合里边呢,记录的就是哪些类呢,是由它加载的,所以它有个关联关系,那以及呢,我们通过这个大的class呢,可以叫get class loader获取呢,这个类是谁哪个加载器给它加载的,包括呢,我们这个类的话呢,可以去创建不同的实例,那我们就相当于叫实例化了,那实例化当然方式也很多,对吧?然后以及呢,通过具体的一个实例呢,咱们还可以调用get class方法获取呢,是由哪个类创建的这个对象。
04:33
那么这个呢,大家都应该比较熟悉啊,那么这个类的加载器啊,咱们说在这个JDK1.0的版本当中,其实就已经出现了,主要目的呢,就是加载一些我们Java中定义的这些小程序,但是如今的话呢,类的加载器已经是比较强大了,它在我们说这个OSCI就涉及到热部署啊,热代码替换这样的场景当中,以及呢,对这个字解码呢,进行加密,解密这个领域呢,大放异彩,因为咱们讲过第一第一章和第二章之后,嗯,大家知道这个自解码文件呢,咱们可以自己呢,是不是去解析,然后呢,给他反编译出来,基本上能够得到这个源码,对吧?那如果说呢,你希望这个自解码文件呢,既让别人用,但是又不希望呢他这块。
05:14
直接呢,通过反解析的方式,反编译的方式呢,把它还原回来,我们就涉及到这个加密和解密的问题,那这块的话呢,我们就可以依赖于类的加载器啊,去实现这个加密的这个,呃,解密的这样一个操作,OK,那么这个能完成这样的事儿呢,主要归功于这个Java虚拟机的这个设计者,在最初设计类的加载器的时候呢,并没有考虑把它绑定在GM内部什么意思啊,就是说并没有说这个虚拟机当中的这个类的加载器,一旦我们定义好以后啊说就不能修改。啊,这个呢,我们这个下边也会讲,咱们还可以呢,是不是叫自定义类的加载器啊,包括呢,咱们还可以去改变啊,叫这个加载过程当中呢,叫双亲委派这个机制。啊,这个都可以去改,所以呢,我们会看到呢,其实Java这个语言啊,这个咱们呢也讲到今天了,大家呢,做Java开发应该也都很长这个年头了啊,这个Java这个语言呢,还是非常开放的,对吧。
06:10
一方面呢,本身这个在每一个这个JDK版本当中都会提供相应的叫open jdk这个版本源码呢,给我们开放,那另外一个方面呢,在Java语言的这个本身当中,当然你会发现呢,就是我们像定义类啊,系统提供了大量的这个类库,我们还可以去自定义类,那我们还可以自定义注解,对吧,那像我们在这个框架当中注解呢就很多了,那我们还可以定义这个异常,嗯,对吧?嗯,包括呢,像这里边提到类的加载器,咱们都还可以去自定义,所以Java这块呢,就是诶给我们提供了丰富的这样的一个一些接口啊,就是你可以呢,用系统现成的,那么大部分呢,系统给我们提供的呢,这里给我们提供的,那都允许我们自己在做一些这个自定义是吧,这呢就是非常灵活的一些地方,好这呢就是我们说的这个那类的加载器,这样的一个历史上的一个描述。
07:02
那这块呢,关于这个类的加载器这一块,那主要呢,其实体现的就是关于这个双亲委派模型这块,在面试当中呢,问的会稍微的多一些,包括呢这个诶有没有打破双亲委派模型这个机制的这个点是吧,它的优点是什么,双亲委派机制的优点什么,缺点是什么等等,那这个呢,咱们这一章都会讲到。都会讲到啊,所以这块呢,这些名人题咱不一个去讲,等我们讲完这一章,大家再回过来看啊,就so easy OK,好,这是这个问题,然后呢,我们再来回顾一个叫类的加载的分类。注意不是类的加载器的分类啊,是类的加载的分类,这呢我们分成了两种情况。一种呢叫做显示加载,一种呢叫做隐式加载。就是我们现在呢,在这个程序当中要使用一个类了,对吧,那这个类呢,我们这个怎么把它加载进来,这样的两种方式,所谓的显示加载呢,就是我们主动的通过代码的方式把这个类呢加载过来,比如说呢,咱们使用class.for name。
08:05
这是咱们在这个反射当中呢,这个会用到的一个操作,主动呢,我们加载这个全类名所对应的那个类,对吧?那我们把它呢,主动的加载过来,或者呢,我们使用这个类的加载器调用呢,叫load class,那里边儿呢,也是填写上我们这个类的全类名,那也可以呢,进行一个加载,这呢都属于叫主动加载。对吧,那这呢就叫做这个主动加载,那么所谓的这个隐式加载呢,就是我们没有直接通过代码编写的方式呢,去使用这个类,那剩下这种呢,都属于这个叫隐视加载,比如说呢,我们在一个类的这个class文件中,比如一个方法里边,我们调用了另外一个类的对象,那这个时候呢,额外的这个对象,嗯,这个比如说你要new是吧,New这个对象,那你这个new的这个结构呢,我们还没有加载到内存中,那这时候呢,就需要把它进行一个加载。OK是吧,那这个事儿呢,其实也比较好理解,比如说呢,我这块呢,写了一个非常简单的一个类啊,叫做user类里边呢有一个属性,对吧,那我现在呢去。
09:04
又一个。一个呢,叫做user的一个test。好,然后在这呢,我写一个main方法,首先,然后呢,我们去创建一个user色的实例,这样对吧,那这呢,你也可以加上一个它的叫two的方法。行写完了来回过来,那这个时候呢,你看我们写了一个呃代码是吧,这呢就我们创建了user这个类的对象,当我这块呢去执行的时候,对吧,我去执行的时候,咱们呢,在第三章也讲到了这个,我们有一个没方法,这个没方法它所属的这个类呢,是不是我们算叫主动使用对吧?啊还会涉及到这个类的一个初始化,OK,然后在这个main方法当中呢,我们需要呢,去这个调用user这个类的一个构造器。那你调用墓道器的前提是这个类呢,必须要加载到内存当中,所以这呢就涉及到它的一个加载问题,那涉及一个加载问题,这呢就属于呢,我们称为呢,叫什么隐视的。
10:04
加载对吧。对,这个呢,就属于这种叫演示的加载,那所谓的显示加载呢,就是刚才提到了咱们通过class.for name的方式,那我把这个user。哎,双击选中点右键啊,拷贝一下它的这个引用CTRLV粘过来,那像这样的方式呢,咱们称为呢,是不是叫做。哎,这个显示的一个加载对吧。哎,这样的方式,哎在这呢,我们说明一下叫诶显示诶加材行这个呢,就是咱们说的这样场景,包括呢,刚才说的这个class,嗯,这个也是,比如说我们通过class loader.get比如system class load点我去load一个class,那还是它这个呢也是叫做显示加载。OK,这呢就是显示加载行,那演示加载呢,平时咱们这个各种场景中见到的也很多,这个呢就不多说了,包括你通过类呢,直接调它的静态的属性啊方法呀,都算是在日常开发当中呢,咱们属于混合使用。
11:07
啊,这个很好理解啊,不多说,然后下边呢,我们再谈一谈,咱们现在要讲这叫类的加载器,这个讲它的一个必要性是什么呢?那这里边儿提到了一些这个日常我们见到的一些需求,比如说咱们在开发中见到了叫class not found exception,或者呢,遇到了说no class DeFine found error,那遇到这样的情况下的话呢,你得知道是什么原因造成的,那我们就需要呢,考虑到这个加载器加载这个类,为什么加载不进来呢?那根据这个日常的这个错误信息,错误的这个日常的这个日志信息,我们去定位解决对吧。下面来说这个需要支持类的动态加载,以及呢对编译后的自节码文件呢,进行加密解密操作的话呢,我们也需要跟类的加载器去打交道,那刚才呢,不也提到了OSGI,还有这个加密解密的问题是吧?这呢就需要我们去跟这个自定义的类的加载器呢去打交道,那下面呢,就是开发人员呢,可以在程序当中编写自定义加呃,自定义的那个类的加载器来重新定义类的加载规则,实现一些自定义的一些处理逻辑,比如说呢,我们在上篇呢也提到了叫双亲委派模型,那我们在自定义类加载器的时候,完全可以不遵循双亲尾派模型。
12:17
那那双新美白模型呢,有它的优势,也有它的劣势,那它的劣势方面,你可以通过自定义的方式,诶,比如说做一个重新的规划是吧,按照自己的逻辑呢,进行一个处理好,那这呢就可以整个理解成咱们讲这个类的加载器的一些基本概述。
我来说两句