00:00
那下边啊,咱们就来看一下具体的该如何实现啊,自定义类的加载器啊,该如何去实现好,那不管是我们自定义也好,还是呢,我们系统已经提供好的,像系统类加载器,还有这个扩展类加载器也好,他们呢,都是你看都是间接的,是不是都继承于叫class。那很自然而然的,我们要想自定义的话呢,是不是也要去继承于它对吧?那关键就是你看是直接继承还是间接继承啊,你像这个这两类呢,都是间接继承的,他们的直接负类呢,是叫URL classo,那咱们呢,你要说出于简单起见呢,你也可以呢,直接去继承UR classo,那这呢,咱们就诶不选择它了,直接呢,我们继承1CLASS order啊其他呢也一样,像咱们讲那个异常等等,你要想自定义异常类,那你直接呢,得是继承于异常的这个体系结构,对吧。那我们这块呢,你想自定义这个class loader了,那当然了,你得继承1CLASS loader啊,这个非常容易理解,那关键就是我们继承之后呢,我们需要呢,去重启的方法是什么。
01:00
我们在讲解这个源码的时候呢,提到过两个方法,一个呢叫做load class,一个呢叫做find class,而且它俩之间呢,是不是还是有关系的呀。那它俩之间的关系是什么呢?来,我们看一下这个源码。啊,关于class loader打开啊,我们调用一下这个load。Class,对吧?啊,点开它这个load class呢,它调用了自己重载的另外一个方法,那主要呢,就涉及到我们是不是在加载的同时呢,进行解析的问题,啊for呢,就是不解析,然后再进来,在这个load class里边,我们能看到它和find class的一个关系,前面咱们都说过了,就是一个调用的关系,这呢是叫load class,在内部呢,我们调用了这个find的class,那除此之外呢,剩下的这个逻辑是什么呢?咱们前面也带大呢讲过了,这儿呢,就是保留咱们叫双亲委派机制的这个核心代码,对吧。那言外之意呢,就是呃,Load class呢,体现了双性品牌机制,那同时的话呢,你要具体加载的话呢,使用这个find class。
02:04
呃,去实现就是你自己这个呃类的加载器,你要是加载的话,你就调它啊,因为呢,双节器有可能是不是负类呢,加载是吧,负类要没加载到你这儿了,你要是你加载你就调这个find class就行,那这呢就我们说的这个关系,那咱们现在呢,你是选择重写这个load class呢,还是重写我们这个find的class呢。啊,那这里边儿的结论就是建议大家啊,去重写这个find class。那包括呢,咱们在讲到这个破坏双擎语派机制的时候呢,其实也提到过这个事儿,对吧,那他不建议我们去重写这个load class,而是呢,你去重启这个叫find class,呃,尽量的让我们去保留是不是双亲委派的这个机制的这个模型,对吧。所以呢,我们重写这个find class呢,第一个好处呢,保留双语模型,那再一个它的大环境下呢,进行小范围代码的一个改动,那我们就去重写这个find class啊,这就可以了,这个呢是咱们的一个推荐写法,那另外一个层面来讲呢,有同学说那我就选择重写这个load class,那在这里边呢,我把那个双擎品派机这个代码我再保留下来啊,那不也可以吗?啊当然没问题,但是这样来看的话呢,是不是又存在一个冗冗余的问题,对吧?
03:16
啊,没有必要,所以呢,大家呢,正常情况下你就重写find class呢就OK了。啊就OK了,但是当我们定义好自定义类的加载器之后呢,我们去调用的话呢,大家啊,还去调用咱们的load class就行啊,还去调用这个load class OK,那下边呢,这个说明就是咱们定义的这个,那自定义的类的加载器呢,它的负类加载器呢,是系统类加载器啊这个大家了解一下这个事儿,那另外的话呢,就是呃,这呢跟咱们自定义其实关系也不大啊,就是整个呢,关于类的加载器的一个说明,就是咱们说所有类的加载呢,其实使用的除了是你自定义的这种啊,你覆盖了这个呃,Class loader这类中的load class这种情况除外。除了这个情况之外呢,咱们Java当中的所有类的加载,其实调用的呢,都是class load里边的这个方法。
04:04
在这个方法里边呢,哎,这不是体现双性委派机制,你该是哪一个级别的类的加载器加载就用哪个级别,那咱们现在是不是建议呢,你是不是也不要重写这个方法,那young I呢,就是所有类的加载都是用的这个方法。对吧,哎,都是用这个方法啊好,那这块呢,说清楚之后呢,下边咱们就来具体的去实现一下,我们呢,先新建一个具体的包。啊,我这个呢,比如叫JAVA2是吧。在这个下边呢,我们去定义一个啊,叫做my class。哎,让他呢去继承于class豆,好,那这呢,我们就先写好这样的一个报是吧,一个声明自定义。哎,Class行,那这个呢,假设你要定义好以后,我们希望呢,哎,我再写一个叫MY。Class的一个测试对吧,在这个测试里边,那我这块呢,就会创建啊my class。
05:04
啊,这是咱们自定义的这个JAVA2这个下边的啊,前面呢,是我们之前写好做一些其他测试里边的一些这个操作了,好那这时候呢,你看我们就创建了一个。这个my class loader对吧,那创建好以后呢,我们希望呢,拿着它点去调这个叫load class,哎,这块你告诉我具体那个类啊,准确的说呢,应该是那个自解码文件在哪,我们就做一个加载就行了,是吧,它是这样问题,那我们这块呢,比如说呃,咱们要加载,举个例子啊,咱们在障碍一里边,我们生成了一个自节码文件叫DEMO1,然后把它那CTRLCL一下,那比如说呢,这里边我把它放在一个比较容易识别的位置吧,比如说这个D盘下。放在这了哈,好,那把它呢就关掉回过来,那这样呢,我们这个name呢,哎,我就希望呢,它就叫DEMO1。哎,DEMO1是吧,那这时候DEMO1你注意是咱们刚才放的那个D盘下的那个DEMO1啊,那这时候呢,我们实际上呢,需要一个具体的路径,好那回过来我们这呢,就做一个具体的声明说,比如说呢,叫private string类型的啊,我叫这个自解码文件的啊,Better code它的一个pass。
06:11
OK吧,然后呢,我们通过这个构造器当中,哎,调用的时候呢,对我们这个进行赋值,那首先我们调用这个公参的啊,哎,把我们这个参数呢,给它加上去。这是一个对吧,啊,当然了,当然你也可以去呃调我们另外这个带参数的这种场景。来把它加上啊,这个OK一下啊,这就相当于我们再去new用这个class的时候,你还指定你可以显示的指定你的这个parent是吧,哎,这样的情况好,那这块呢,回过来啊,这个就报错了,我们就可以填写,咱们刚才是放到这个D盘下。哎,在D盘下呢,找这样的一个词解码文件对吧,哎,就是这样一个意思,好了,那再回过去,我们呢,刚才提到了重点需要重写的是不是,就我们叫find,诶,Class是吧。哎,把这个方法呢,我们进行一个重写啊,那就别调这个修了啊,行,那现在我们有的呢,是一个文件的一个具体的一个名字,那根据这个名字的话呢,我们就具体的去这个把它对应的那个路径下的那个文件啊,给它加载进来啊,最终呢,是要生成一个大的class的一个实例是吧,那这时候该怎么弄呢?啊,咱们这块呢,就使用前面讲的这个IO流来做了。
07:21
嗯,IO流的话呢,咱们这块呢,用一个缓冲流来处理吧,我就拗一个,哎,就直接这样写了,哎。Buff啊。Buffer的input stream。来new一个啊,Buffer啊,Input stream,这new一个file input streamam啊这呢,具体的就是一个file了是吧,这个file的话,我前面呢,这样再写一下,在词针类型的我们这个file name。这个file name的话呢,注意它是不是需要搭配上,咱们刚才说的叫better cold pass是吧?哎,它呢在匹配上,哎咱们这个具体的name,这个name的话呢,实际上是咱们的一个class的一个name。啊,你把这个名改一下,这都可以的是吧。
08:03
啊,是我们这个class name,然后具体对应的它的这个结尾呢,是一个自解码文件啊,所以这样写一下,然后把我们这个file name呢,咱们给它添加到这。哎,这样就可以了是吧,好,那我们这个在find class里边,前面呢,咱们其实也讲解过,它会呢发起对这个叫DeFine class的一个调用。他会调咱们那个DeFine class,这个DeFine class呢,它主要需要一个什么呢?需要一个二进制的一个数组,或者叫二进制的一个数据,那关键呢,我们就希望把你这个文件当中的这个数据呢,是不是读到内存当中形成一个呃字节数组啊。那所以这里边呢,我们要想形成字节数组,哎,这呢,我们借助一下叫be a RA啊,Output stream这样的一个流。啊,我就这样就写了啊,Battery out to the stream啊读到这个内存当中就行,好下边呢,就是具体的咱们实现的这个细节了啊这个就先写这比如每次呢,我们就读1024字节课啊这呢是一个八号循环。
09:08
呃,bis.read到咱们这个发货当中。哎,这个八伏了,好像叫data了是吧,然后返回它这个长度,我们用这个L1呢做一个记录,这个长度呢,如果要不是负一表示呢,这个数据呢,没有读完。咱把这个数据呢,哎,写到啊right啊,写出到咱们的这个。嗯。这个battery output当中啊,从零到。好,那么通过这样的一个循环操作呢,我们把对应的你这个文件当中的这个数据呢,就都写到咱们这个内存对应的这个batter RA output stream对应的里边那个字节数组里了。啊,这就写进去了啊,那写进去之后呢,那我们下边呢,你把这个数据呢,整个给它取出来。啊,Bos点我们叫To Ber是吧?哎,得到它,它呢就能得到一个字节数组啊,Be。
10:06
啊,这个扣OK,那这个数据呢,我们就接下来可以调用,咱们这叫DeFine class,那把我们这个bad扣呢。哎,给它放进去啊,从零开始,一直到我们这个数据呢结束。OK啊,这就成这就可以了,那这呢,就是咱们整个这样的一个算是实现的过程啊,当然最后的话呢,我们需要呢,进行这个流的一个关闭啊bos点。来做一个close的操作啊,我们这个BS点啊,Close的一个操作是吧?行,那这里边儿呢,我们把从这到这呢,给它包起来。来做一个这个的处理。哎,把这俩呢,我们再扔上去。分别呢,再进行一个try catch。好,为了保证它不出现控制人异常,再加上一个判断。
11:12
嗯,这样就可以了是吧。好,这呢,就是我们定义的这个叫find class啊,咱们把简单的这个注释说一下啊,首先呢,这个呃,我们叫哎,获取这个字节码文件的一个完整路径。啊,完整路径,然后这呢是获取一个输入流,哎,下边呢就获取一个输出流。哎,这样子,那下面呢,就具体读入数据并写出数据的过程。哎,具体并哎写出啊的一个过程,哎把这些数据呢,我们就写到咱们内存当中,这个betterable stream内部对应的一个字节数组当中了,好,那这呢,数据写完以后呢,我们就哎获取。
12:01
啊,内存中的啊,这个完整的。这个哎,字节数组数据。看这个数据好,这些数据呢,就相当于是咱们完整的那个自解码文件的那个数据了,好,那下面的话呢,我们要去,诶调用那咱们叫做a DeFine这个class啊,将字节数组的数据。调理方法。啊,字节数组的一个数据转换为,啊,转换为我们大的class的这个实例。哎,这个呢,不光是我们自定义的这个类加载器这样来做,那系统的这个相应的其他的类加载器也得需要最终调用,我们这叫DeFine class这样的一个方法啊,这个方法呢,返回值其实就是我们大的class的一个事例,哎,那我们在这呢,直接做一个return就可以了。啊,Return就行是吧,那如果说你这块出现相关的异常的话呢,我们那你最后这块呢,在这一个no。
13:06
哎,这样就OK了。好,这呢,就是我们整个这样自定义的这个类的加载器。好,那这个写完之后呢,我们下边来进行一个测试是吧,现在呢,我们漏一个class,就是咱们一个叫代一,那我放在D盘的一个下边了,找一下我们这个D盘。在这呢是吧,好没有问题,那回过来的话呢,我们这个呃,Load class呢,本身会抛异常,那在这呢,我们来一个try catch。啊开,那此时呢,加载我们是不是就能得到具体的一个class了,是吧,那咱们知道这个class呢,其实代表的就是咱们这个DEMO1的这个哎class class啊行,那这是我们打印一下说呢加载。哎,此类的类的加载器为,诶我们后边呢,调一下这个,哎,class.get class load。
14:00
啊,那你也可以是get一个class是吧,底下get个name啊,完整看一下它的名字是什么也行好一下。好出来了是吧,那这个时候呢,我们加载的D盘下载这样一个自节码文件呢,它使用的类的加载器,就是咱们自定义的这个。那是没问题的是吧,那下面我们再来看一下说这个词啊,类的加载器的这个复类是什么。哎,当前类啊,加载当前。哎,一。类的啊,类的加载器的这个负类加载器为。啊,有点绕是吧,哎,这个呢,就是这个class,第2GET class shoulder,第2GET super。Get class get parent是吧?哎,就是看到它的一个负类加载器,然后再点一下,你可以get一个class。
15:06
Get class第二啊,再去get一个name是吧。这样的啊。好,这就出来了,就是加载咱们当前这个DEMO1这个类的类的加载器,其实呢,就是我们这个my class loader它的负类加载器,那大家会看到就是我们说的系统类加载器啊,这呢也验证了,就是我们这块呢说的这句话。那这句话就是我们在这里边儿呢,并没有直接的去定义咱们当前这个类的加载器,它的这个父类是谁是吧,那默认情况下呢,就是我们说的系统类加载器啊,这是我们调用的这个加载这个结构呢,仍然是用的这个load class的方法。啊,是这样的一个场景,好,那这呢就给大家举了一个我们自定义类的加载器的一个例子,啊,大家下来呢,也可以自自己呢去写一写,好这呢就是我们关于这个自定义类的加载器的一个说明。
我来说两句