00:00
好,下边咱们看一个概念啊,这呢我们称为呢叫类加载器的命名空间。那首先呢,我们来说明一个概念,叫做类的唯一性,我们在这个应用程序使用过程当中啊,呃,通常呢,我们使用的一个类呢,都是唯一的,那这里边儿我们要判断怎么才算叫这个类是唯一的啊,比如说呢,我们内存中的两个类,这两个类呢,是来自于同一个class文件。那来自于同一个class文件的两个类,它就是唯一的吗?对吧,那同学会想说,诶,本身不应该发生这样的行为啊,说我们说一个资金码文件呢,加载到内存中,呃,对应的一个类,这个类呢,不应该是只被加载一次嘛,这个正常来讲是这样子的,但是这里边儿有个前提是因为我们加载这一个class文件的时候呢,咱们使用的也是同一个类的加载器。同一个类的加载器,所以呢只能加载一次,但是我们现在呢,如果你有两个类,它确实来自于同一个class文件,但是呢,它们是被注意不同的类的加载器所加载的。对,那就是这个意思,比如我们这呢,有一个对应的一个class文件,然后我现在呢,使用是class loader1是吧,然后还有一个呢,叫class loader2,咱们先简单这样来说,我呢是用CLASS1呢去加载我们这个自解码文件,那生成内存当中就是一个对应的类模板结构,对吧?那么CLASS2呢,它也去加载这个自解码文件,那得到内存中呢,就是我们这个类模板的结构,这个我叫A,这个我叫B,注意此时的A和B。
01:28
就是两个不同的类了。我们就把它看成是两个不同的类,那也就是说呢,我们比较两个类呢,是不是相等,那只有在这两个类呢,是在同一个类的加载器的加载下啊,它才有意义,那如果是不同的类的加载器,那它俩就显然是不相同的。这个概念呢,大家呢,需要明确一下啊,需要明确一下啊,这个跟咱们一开始的这种认知呢,可能不太一样,因为以前呢,我们更多的其实没有关注于类的加载器,对吧?那我们相应的比如说咱们在这个应用程序当中,像这个user也好,像这个user t也好,这都是属于咱们自定义的类,对吧?那么自定义的类呢,默认使用的就是系统类加载器。
02:13
那这个程序在执行起来之后呢,它会创建一个系统类加载器的一个实例,帮我们去加载这个类,加载这个类,那那如果说我们在另外一个场景下,我又拟一个userr,如果你使用的还是这个类的系统类加载器的话呢,那这个时候呢,其实诶,我们就不会再去重重复加载了,因为是唯一的嘛,对吧,那这是我们说的这个场景,但是呢,我们原来相当于是没有去接触这个内在加压器,现在呢,我们具体讲这个问题的话呢,哎,大家得需要去明确。啊,相不相等依赖于你这个类的加载器是不是同一个对吧,类的加载器变了,那就不是两个相同的类了。那这个命名空间呢,就是针对我们说的类的加载器来说的,说每个类的加载器都有自己的一个命名空间,那这个命名空间呢,由该类加载器还有呢,它所有的负类加载器呢,所构成的,在同一个命名空间当中。
03:03
同一个命名空间中不会出现类的完整名字相同的两个类。这呢,是不是就对应的咱们原来说的,原来呢,咱们就指的是这个针对于某一个类的加载器,或者咱们没有明确指出类的加载器的情况下,我们说一个类呢,是不是只加载一次。这里边所谓的只加载一次呢,就是因为这个类呢,它在这个类加载器的命名空间中,它就只能够存在一个,那你再加载的话呢,不能再加载了,那只能是用你之前存在的这个,在这对应的就是咱们以前讲的只加载一次的概念啊,但是如果呢,你要是在不同的这个命名空间当中,就是在不同的类加类的加载器当中,我们是完全可以出现两个同样包名的这样的类的。也就是说呢,我们可以加载两次,那就是这样一个概念啊,那在大型的应用中,往往我们借助这个特性呢,来运行同一个类的不同版本。那这块呢,就涉及到像我们这个tomcad,这个属于叫外部服务器了,对吧,我们可以在tomcad当中啊,咱们定义多个不同版本的啊,叫类的加载器,然后呢,我们在同针对同一个这个web应用程序呢,我们运行不同的这个应用程序啊,同一个web这个应用服务,我们运行不同的应用程序,实现一个具体的,比如这个类呢,我们在这个类的加载器中进行加载,然后诶,同样的这个class文件呢,我们在另外一个类的加载器中进行加载,实现应用的一个隔离。
04:27
哎,这个呢是非常有用的,也比较实用。那举个生活中的例子,就好比是什么呢?呃,这个大家呢,你在中国呢,比如国内咱们写了一个论文,然后你发表到这个,呃,国内的这个期刊上,那国内的这个期刊呢,咱们可以理解成了,就好比是叫类的加载期,对吧,这是国内的期刊,然后呢,诶,你同样的这篇文章,然后发表到这个,诶比如说美国的这个期刊上了,啊就是在这个大家你可以把它就想象成哎,看作是不同的这个类了,是吧,不同的这个文章了。那就是这样子的情况,嗯,OK,行,就是这个例子,当然不是特别合适啊,咱们正常来讲的话,你一篇文章,不管是用中文的还是用这个外文的,应该是算成一个的,对吧,那现在呢,我们就在不同的场景下去加载,我们就认为你是不同的啊,就是这个道理,那这呢,给大家举个例子。
05:16
给大家举个例子,我这儿呢,提前已经写好了一个叫自定义的类的加载器啊,这是一个自定义的类的加载器,咱们在后边呢,会讲如何呢,去这个实现一个啊自定义的类的加载器,我现在就是重心不在这儿,所以咱们提前给大家写好了,那写好以后呢,我下边呢给大家来做一个测试啊,咱们一起来看一下,我这呢先写一个main方法。啊,然后呢,我们要加载使用当前这个类的加载器的这个实例,咱们去加载,比如说user这个类的话,那首先呢,我们得表示这个user这个类,咱们先这样一下啊。Open in terminal。在这我先Java飞一下,然后a user。第二,Java。行,那我现在在咱们当前的这个目录下,嗯,啊刷新下已经出来了,当前这个目录下呢,去生成了一个这样的自解码文件,然后呢,我把这个自解码文件所对应的这个结构呢,咱们给它使用user class load的实例呢,进行一个加载。
06:13
啊,OK,进行加载,那首先呢,这个优色点class,它所在的路径呢,是我们说的这个路径是吧,我们先把这个路径呢,诶给它呢,获取一下啊,这个咱们定一个string型的,比如叫root的D啊这个路径呢,咱们应该是到这啊把它。嗯,有一个叫copy reference。CTRLV,好,哎,不对,再来一下pass啊。好,这个粘过来,呃,这个src到后边,我们把它也得加上个这个斜杠啊,在他这个路径下,我们现在去创建具体的这个,呃,User class先去new一个user。Class load,然后呢,在这里边把咱们这个root的DR就表示呢,我们这个class load呢,它加载的是这个路径下相关的这个自解码文件,好,那我们创建一个这个我就LOAD1。
07:07
哎,创建个它行,然后这个LOAD1第二我们调用一个方法,这个咱们后边会讲这个class里边具体的方法,这个方法呢,叫做find class,这个find class呢,就指明咱们当前呢,你要加载的是哪个自间码文件啊,对应的这个结构是不是我们这个右侧点class对吧?它所对应的这个全类名呢,你在这写上。com点爱的硅谷点Java下的。哎,叫做user是吧。好写上它呢就可以了,然后这个饭呢,这个加点呢,它会抛异常,那暂时咱们把这异常呢,也都给它做一个拆开纸的处理啊,这个放里边也行啊。那此时的话呢,我们就能够得到一个具体的class的一个实例了。哎,我这时候呢,称为叫CLASS1没问题对吧?行,那我现在同样的呢,我再CTRLC一下,我在创建一个这个class load。这个呢,我们称为叫叫LOAD2,然后这个LOAD2呢,我们也再去加载一个这样的一个存解码文件对应的这样一个类,对吧,那我叫CLASS2,这个正常来讲,我们说呢,嗯,只能加载一次是吧,但是呢,由于咱们现在呢,是不是显示的创建了两个类的加载器啊。
08:16
哎,创建那这个是自定义的啊类的加载器一是吧,然后把它呢,CTRLL一下,这个呢,是我们创建的第二个。好,那创建两个呢,我们分别去加载的话呢,这个我们就提到了,这个在各自的类的加载器的命名空间当中,我们只能存在一个user,然后在你你这个类的加载器的命名空间中,你存在一个user,实际上这两个呢,我们就会被加载两次,简单来看的话呢,如果我们使用叫CLASS1,是否等等于CLASS2来进行判断,那这个结果我们跑一下。啊,这个首次加载的话呢,会稍微慢一些。
09:04
好出来了,这时候大家会发现呢,你看这个结果是个false,那也就是说呢,咱们这两个,诶这个大的class这个实例指向你方法去的类模板,那个模板的地址是不一样的,对吧?说明呢,就是有两个,那进而的话呢,大家也可以通过这样的操作,比如说class,诶一点我们get class loader看一下这个CLASS1,它加载的这个贝ATE加载器是谁,以及呢CLASS2,那我们再去做个执行。好,这时候呢,大家就会发现,那我们都是这个user class load,具体这个自定义的类的加载器的实例,但是这两个实例呢,显然你看不一样对吧,那就意味着呢,咱们现在呢,就是这个CLASS1呢跟CLASS2,虽然他们加载的是同一个自建码文件这个结构,但是呢,他们使用的类的加载器是不同的,所以这呢,我们就称为这个诶CLASS1是吧,它与咱们的这个CLASS2啊是对应了,是不是不同的啊,叫我们称为它叫类模板结构对吧。
10:05
嗯,相当于呢,在方法区里边,这有一个,嗯,这个user对应的一个类模板结构,然后还有一个这还有一个user,那我们是用两个不同的内在加载器量进行加载的啊,那我们在实际开发当中呢,像刚才提到他CA当中,我们就可以借助于这样的一个点呢,实现这个应用的一个隔离。好,这是这个情况,那以前的时候你看咱们怎么做呀,咱们在使用这个,嗯,自定义类加载器,之前以前我们加载类的时候呢,像针对于user这样的类,咱们都是使用的是不是系统类加载器啊,那我们现在可以试着呢,来操作一下这个class load点,我们有一个get system class就获取系统类加载器,第二咱们主动的让它去加载一个类,那加载的话呢,是不是还是这个user啊。没问题是吧,好这样呢,写完以后我们al enter一下,然后这块生成的这个class。哎,这个我成为一个三行,那我们也打印一下这个class。
11:02
三是吧,我打印一下它点get class loader吧,那这时候呢,我们运行一下看看。哎,出来这个结果了是吧,那这时候出来这个结果,大家自己操作的话呢,你要这个稍微注意一下啊,就这时候我们这个user。啊,注意这个user咱们刚才呢,是不是执行过,在这个里边执行过,对吧,那我们这里边呢,你要去做一个执行的时候呢,其实它就会给我们这个user呢,生成对应的子解码文件,这个自解码文件呢,你注意是在下边啊,你看这个userr呢,咱们在idea当中给我们自动的进行编译之后生成的自解码文件不是在这儿,是咱们刚才自己让它这个加载到这儿的。然后呢,它会生成在咱们的这边。大家会发现是不是在这儿了,哎,这个小细节大家需要注意一下,什么意思啊,就是你看啊,我把这个子解码文件呢,做一个删除。这个呢,是系统自动把我们生成的这个优点class我删除了,删除以后呢,这个大家再回来看,我此时呢做一个执行。
12:08
你看这时候就挂了对吧,所以这里边这个小细节呢,大家要注意一下,就是我们上面这个加载的这个路径呢,是咱们自己指定的这个路径,而对于我们这个还是使用原来的系统类加载器主动去加载的话呢,它这个时候呢,还得使用咱们默认的情况下,你在这个al里边的这个路径,因为呢,这个时候你看咱们没有把这个user类是不是加载过来。那就是编译,你得先编译是吧,没有编译过来,所以呢,这时候他就找不到我们这个啊文件了是吧,叫class not found exception这个呢,就我们那会儿也提到了这样的一个异常情况,那需要怎么办呢?需要大家呢,就是你打开这个user呢,给它做一个编译。那这时做个编译啊,编译完之后呢,我们刷新一下,这不是在这就出现了,然后呢,你你在这个位置去加载我们这个类啊,它就可以了,它识别的呢,就是我们下边这样一个路径。
13:01
啊,识别这样路径,然后这时候它加载的话呢,那使用的就是我们说的系统类加载器,对吧?OK,那这时候呢,大家会看到咱们实际上那基于现在有三个类的加载器,是不是各自呢,加载了一个,嗯,加载了一下这个自解码文件,对吧?当然了,下边这个自解码文件严格上来讲,跟咱们上边自解码文件呢,其实是两个不同的文件了。哎,稍微注意一下是两个不同的文件了,当然呢,都是由同一个这个Java类,咱们编译得到的这个资金码文件,就是具体的内容其实是一样的,对吧。行,那通过这个呢,咱们想给大家强调的问题呢,就是关于我们说的这叫什么叫类的唯一性这样的一个判别,好然后下面呢,关于这个类的加载器机制的一个基本特征,那这个大家了解一下,咱们一说呢就能明白啊,那类的加载器的话呢,咱们在上篇呢,也提到过,叫做双亲尾派模型,对吧,这个注意这个模型呢,是JDK1.2的时候呢,加入进来的一个点,或者叫一个规则,那一开始的时候其实也不遵守,对吧,那就相当于我们这里边提到的破坏的第一种情况,就是在1.2之前,咱们没有遵守的这样一个场景。
14:07
啊,1.2之前是吧,没有遵守场景,那这个双亲委派机制的这个好处的话呢,呃,大家呢,咱们在上天呢,其实也提到过,比如说避免类的这个重复加载是吧,确保一个类呢全局的唯一性,咱们刚才不也提到了什么叫唯一性吗。对吧,然后以及呢,保护咱们的程序啊,防止呢,像核心的API呢被篡改啊,这个都依赖于我们说的双新品牌模型,但是它也有相应的一些弊端是吧?呃,下边也提到我们在实际开发当中的一些具体的场景,咱们去打破这个双性伪害模型,咱们在下边呢,那我也会给大家讲到这个情况,那下面一个呢,叫做可见性,它主要指的就是我们子类加载器呢,咱们可以访问负类加载器,那但是反过来呢,是不允许的,那上面咱们也讲过,通过子类加载器叫get parent,对吧,获取这个负加载器。啊,这个反过来不允许,那不然的话呢,因为缺少必要的隔离呢,我们就没有办法呢,利用内接压机去实现这个容器的这样一个概念,啊,这个注意下一个呢,叫做单一性。
15:04
单一性的话呢,就是由于负加载器呢,它的类型对于此类加载器呢是可见的,所以呢,负类加载器中加载过的类型就不会在此加载器中进行重复的一个加载,那这就保证叫单一性是吧?说大家注意类加载器的邻居之间同一个类型可以被重复加载啊,因此呢,呃,这个因为呢啊故相之间是不可见的,这呢就提到了咱们刚才比如说咱们用是不是同样的呃,User class load的两个具体的实例,两个类的加载器,那去加载了同一个这个结构对吧,那这个时候呢,它俩其实就相当于是两个邻居啊,就是同一同一行的这样的啊,这个结构不是咱们说的,这是子加载器,这是负物加载器,不是这个概念,是同一级别的对吧,是可以呢,出现多个的。啊,出现多个的行,这呢就是我们提到关于这个命名空间啊,包括类的唯一性的一个介绍。
我来说两句