00:00
那接着的话呢,我们来看下边这个问题,那讲完这个克拉斯的这个源码解析之后啊,那其实我们可以考虑呢,就是来讲这个自定义类的加载器了啊,但是在这个之前呢,我们把这个双亲尾派模型呢,再给大家呢,稍微的描述描述,包括呢,我我们在提提像面试当中有时候呢,经常会被问到的说双亲尾派机制我们一定要遵守吗?对吧?那如果要不遵守的话呢,破坏行为有哪些具体的体现呢?那请举例说明,那这儿呢,就涉及到我们这样的这个面试的问题,那包括呢,我们在上篇提到双擎委派机制之外,是吧,那我们对他呢,希望有一个更深入的了解,那这儿呢,我们来看一下这个关于那双擎委派机制这个模型的一个说明。那么前面这个内容呢,咱们在讲上品的时候呢,其实是提到过的,那咱们稍微也算是一个复习,那从注意JDK1.2版本开始,那类的加载过程呢,就采用双亲委派机制了。那从JDK1.2这个版本开始,好,那么这个定义是什么呢?这个就比较熟悉了,说如果一个类的加载器在接到加载类的请求的时候,他自己首先不会尝试加载这个类,对吧,而是呢,把这个请求呢,委托给他的负类加载器呢去完成,那负类加载器呢,在依次递归,然后找它的负类啊,依次往上,依次往上,那其实最终呢,就找到了引导类加载器,那判断一下这个引导类加载器它是不是可以完成类的加载任务,如果是的话呢,那就直接返回,因为我们说呢,对于一个类的加载,我们要保证它的这个算唯一性是吧,加载一份就可以了啊,那如果这个父类加载器它不加载的话呢,那我们这时候呢,就交给它的子类加载器,子类加器,一看还不加载,那就再往下委托。
01:38
哎,再往下去传递给我们在下层的这个类的加载器呢,去加载。对吧,那这边也提了写到了,只有负类加载器无法完成此加载任务的时候,我们才自己呢去加载。本质上来讲呢,我们其实规定了类加载的一个顺序,对吧,那首先呢,相当于是由引导类加载器呢先加载,如果加载不到呢,那交给扩展类加载器,那还加载不到,交给系统类加载器,或者是我们还可以自定义类的加载器呢去进行加载。
02:08
啊,这儿呢,就是我们说的叫双亲尾拍机制,它的一个,呃,具体实施方面的一个特点啊,这儿呢,也画了一个图,对吧,你看这也画了一个图,就是一开始的时候呢,由我们系统类加载器呢,去判断那是不是加载过,那如果加载过了,那肯定是不用再加载了,没有加载过,再往上委托那看一下我们扩展类呢,是不是加载过,那加载了就不加载了,没有,那接着往上走到我们引导类加载器的时候呢,呃,如果也加载过了,那就不再加载,那加载一次就可以了,对吧?那因为在我们相应的这个类的加载器的命名空间当中,我们说这个同名的类只能有一个,对吧,保证它的这个唯一性啊,那如果说呢,这个引导类加载器没有加载,那我们看一下你适不适合加载,是适合加载,那你就你加载不适合加载,那就往下传递给我们扩展类,扩展类同样的道理,再往下扩展到这个系统类这块,那是适合加载那就加载,不适合加载,那通常呢,我们也没有定义这个,呃,自定义类的加载器是吧,那系统类加载器呢,也是咱们使用频率最高的了,它这块还不去加载,那就报。
03:08
Class not found exception。哎,这呢,就是掌握我们说的这个流程啊,那举一个生活中的例子的话呢,嗯,像是什么呢。呃,这个大家小时候有没有过这样一些场景,就我们上这个一年级二年级的时候,有时候学校呢,会留一些这个手工课,或者一些这个制作一些课是吧?当然这个东西呢,咱们做不了啊,比如说这个元旦的时候呢,希望呢,哎,大家做一个贺卡,然后呢,小朋友之间互相的分发一下,或者教师节的时候呢,这个班组长组织大家说,诶这个给老师们做做贺卡是吧,或者班主任组织给任课老师呢做贺卡,那可能特别小,干不了这个事儿,那怎么办呢?呃,经常大家会发现这个我们回家以后呢,是不是就委托给自己的,嗯,比如说这个那哥哥姐姐呀是吧,或者说你这个哎。老妈呀,是吧,哎帮忙给自己做啊,比如说这个,诶老妈不太会做,一看诶这个奶奶会做是吧?奶奶这个手工活不错,那交给奶奶去做了,那如果说你一层的往上传递,那上层呢,能够帮你做这个事儿,哎他就给你做了你这个,哎再给你拿着高高兴兴的就交作业了是吧,那如果说呢,你给这个奶奶奶奶看,哎呀我眼花了是吧,这这个整不了,然后这呢又委托给诶老妈,哎这个老妈一看说哎呀这个最近工作比较忙,说你还是自己做吧,你看这个上层呢,都不帮我们做,最后说哎,那干脆还是我自己做吧。
04:27
对吧,那就成这样的一个情况了,那就有点像咱们现在提到的这个叫这个双亲委派模型,哎,通过这个例子呢,大家稍微的可以可感受一下这样的一个实际生活当中的这个场景啊。好,那么下面的话呢,咱们再来提一下这个双新委派机制的一个优势,这个在咱们前面上篇的时候呢,其实也谈到过这个问题,主要呢,我们提到有两点,那这两点呢,大家就是你别死记硬背啊,就是但是你要也要也要能够说出来,那一提到双击品牌机制,那为什么这个Oracle官方在类的加载这个层面这么重要的层面是吧,因为我们所有的类要想使用了,咱们必须要加载,只要加载的话呢,我们就规范了,叫使用双亲委派机制。
05:12
那为什么要采用这样一种机制呢?哎,我们看第一个。首先呢,它避免了类的重复加载。避免类的重复加载,确保一个类呢,它的是全局唯一性的。对吧,确保它是全局唯一性的,举个例子,比如说啊,我在这块,我就那建立一个测试类啊。我叫class class,一个test。但你想,比如说我们现在在程序当中,我想创建一个object的一个实例。对吧,我想创建它这个实例,那我首先呢,需要对这个object类呢进行一个加载啊,那这里边儿我们说这个object这个类的加载。加载只能使用,那我们说呢,叫引导类加载器进行。
06:03
对吧,你看按照我们刚才说的这个机制,嗯,你要是有这个双擎品拍机制的话呢,OB类它比较特别嘛,它是在我们这个浪包下的是吧,那这个浪包下呢,它是一个比较特别的Java开头的,那首先的话呢,我们系统类加载器呢,这个想加载一看啊,系统里边也没有,也没加载过,那先委托给他的负类或者这加载器呢,一看也没有加载过,那接着往上委托,那委托给我们的引导类加载器的时候呢,诶他呢一看是这个,诶Java开头的是吧,那是属于我们这个核心的API的,那这时候呢,他就做了一个object类的一个加载。啊,它就它就给加载了对吧,那当你要是再来这个加载的时候,我们仍然一次一次往上往上对呃,往上这个传递,那传递到这个阴道类加载器的时候,我们说这个一个类的加载器呢,它的一个实例呢,是不是都维护了一个命名空间呀。这个咱们前面提到过是吧,那在这个命名空间里边呢,咱们是不允许存放两个,或者要加在两个这个,呃,全类名一样的这个类的,那我们在这个导类加载器的命名空间里边发现呢,诶,我已经有了这个object这个类的加载了,所以我们就不会再去加载。
07:13
对吧,就不会再其他的以及的话呢,呃,我们说这个刚才说层层往上传递,那你对于一开始的这个系统类加载器来讲,那咱们因为有了双性品牌机制,就让他往上去委托,所以说呢,他自己呢,也不会去加载这个object。对吧,我们这里所谓的唯一性呢,一方面指的是在引导类加载器这具体的一个实例里边,我们不会有两个object。对吧,这是其一,那其二的话呢,也不会出现呢,说我们系统类加载器加载过了,然后呢,这个引导类加载器呢,也加载了一个,那从我们这个,呃,理论上来讲的话呢,只要你是不同的类的加载器。不同的类的加载器的实例,各自维护一个命名空间是可以呢,呃,是不是各自加载一个object类的对吧?当然你说我们用系统类加载器加载一个类,这个有什么意义呢?
08:03
没有是吧,而且呢,会导致我们程序在操作过程当中很多可能一些错误情况的发生啊,那你每用一个肯定得说明是哪一个类加载器加载的,那一不小心呢,可能就会出现一个转换的错误了。对吧,那我们这里边儿呢,就说你不能让这个不同的类的加载器啊,看到一个类谁都想加载,然后各自加载一份,这个呢,就造成这种重复性。啊,这是不对的啊,这是不对的啊,这个呢,我们使用双区排机制呢,首先呢,明确这个点,什么样的类应该由什么样的类的加载器去加载,这个是确定的。啊,不会出现这种重复加载的问题。好,这是第一个点啊,第二点的话呢,我们说可以保护程序的一个安全,防止核心的API呢被随意的篡改。那这个呢,我们也强调过对吧,像这个object也好,还有我们常用的像日期类型,租类型啊等等等等是吧,我们大量使用的这个API呢,其实都是系统给我们提供的核心API,但是呢,比如我们现在呢,就想创建一个包。
09:10
啊,比如Java点哎这个浪包啊,比如我这里边整一个,呃,整个string吧。对吧,哎哎,写错了啊,这个不是这个包名,上面就别带词论了。方名呢就叫浪是吧,然后呢,我们创建一个类。这个咱们在上篇呢,其实也说到过这个例子对吧,那我这呢,就写了一个词论啊,比如里边我们定一个叫来X型的一个数组啊,Y64是吧,啊就我我这样就简单写了写啊然后的话呢,我们做一个测试啊,比如现在呢,我们写一个啊叫string的一个test。哎,这儿写个没方法啊,我就string,哎,New一个,哎,String对吧,好那就这样写了,那你想想我们在这个程序当中啊,哎,正常的话呢,咱们像用到字符串,那肯定都是,是不是系统给我们提供好的核心的这个APS对吧,正常它的加载呢,应该使用我们叫英雷加载器去使用。
10:04
那这里边你看我也写了个论,那现在我点一下这个论啊,你看这时候呢,点的话呢,它是正常还对接到咱们这个默认的这个系统核心API上,对吧,但是我们这时候去执行的时候。你看我们这时候去执行的时候呢,他报了一个错误信息,说呢这个禁止,我们这个包名呢叫Java点这个浪。是吧,禁止叫它这个指的什么情况呢?就是当我们去加载的时候呢,发现在当前这个包下呢,也有一个这个string。那那这时候呢,我们的加载,那在咱们有注意啊,在咱们有双性派机制的情况下呢,你看这个string,它其实没有报说你加载的是错误的这个string了。那如果你想要是没有双星派机制的话呢,现在这个string,那其实我们自定义一个类,那你要是用系统类加载器去进行加载的话。你要是用系统的加去进行加载了,那我们整个程序中又有又有这个核心API的那个string,那你要是想实现这样个替换,有可能会植入恶意代码是吧?在你自定义这个string当中,那就有恶意代码了,那但是现在呢,我们存在这个双清委派机制,这个时候呢,我们这个string用的其实还是咱们是不是系统提供的核心API是吧?但是呢,这时候呢,我们这个在整个这个编译我们这个程序的时候呢,他认为你这个string前面这个报名是不合适的。
11:24
是吧,这个报名是不对的啊,你这样的话呢,会误导这个编译器是吧,就是你这个在加载的时候呢,这个会误导呢去加载它,或者换句话说呢,由于双性语派机制的存在呢,它虽然没有去使用你这个词string,但是呢,你这个包的这样的写法其实是没有任何意义的,本身我也不会去用。对吧,那就是这样的一个场景啊,所以这里边儿呢,它就禁止我们去定一个包名啊,叫做Java点这个浪。啊,就说有点绕啊,简单来说的话呢,就是说,呃,如果你这块没有双性语排机制的话呢,那你这块加载,那就是系统类加载器帮我们加载这个string了,而这个string呢,对咱们系统当中啊,你你要自己编写当中的string呢,要是实现一个替换,那有可能在这个自定义的string当中会存在恶意代码,那进行这个核心API的一个篡改了,那这是不对的是吧,为了出于这种保护呢,我们就不要这样去做。
12:20
那或者呢,有双星语排机制的存在呢,你就不会实现你自定义的string对核心API string的一个替换。啊,因为人家还是阴道类加在一起来做的,对吧。好啊。行,那这个呢就说到这儿,然后下面的话呢,就提到,那如果面试问到你这个双击委派机制啊,说的比较清楚是吧,那你知道双击委外机制在代码层面是怎么体现的吗?啊,这就相当于我们更深入一层了。那这个问题的话呢,咱们在前面讲这个class load的时候,呃,讲这个class的这个load class方法的时候,是我们当时也重点说过这个事儿,对吧。咱们这个源码剖析这块都写着了啊,那首先呢,做这个事儿,然后呢,获取当前的类的加载器的类加载器,那如果存在负类加载呢,由负类去加载,那么依次这样往上递归,那这儿呢,不就是体现了咱们所说的哎,是不是叫类的双氢位排机制了是吧。
13:15
所以说呢,这个双击委外机制呢,主要的体现就是在咱们这个load class这里边啊这儿呢,我把这个咱们这个load class这个方法的核心的这几个操作呢,我就在这写了一遍。你看首先呢,是在当前类的加载器缓存中去找,看有没有是吧,有直接返回啊,接着呢,看它的负类这个加载器是不是为空不为空啊,就接着调负类的,那反之的话呢,如果当前类的加驶器负类加驶器是为空的,那就说明你是引导类了,那就叫引导类的这个操作,那这是这个主要呢是在二三步那这块体现咱们说的双亲委派对吧,那如果三条路径呢,都没成功,那就调find class来进行这个加载。来进行加载就可以了,那find class里边呢,又调用了class loader里边这个DeFine class啊这个咱们这个前面呢,讲这个主要方法的时候呢,就提到过这一点。
14:04
行,这就完事了是吧,哎,下边关于一个举例子就说的,我不债给雷雷,这个咱们不用多说了啊,这就过了。好,大家看,注意下边这个内容。呃,思考一个问题。说呢,我们双清品牌机制呢,是在load class这个方法当中啊去体现的,对吧?好,那如果说我们把这个load class方法。啊,它这一个protected,我们可以进行一个重写对吧,那如果我要是重写这个方法的话呢,大家注意我们能不能把这个双亲委派机制的这个呃逻辑给它干掉呢。就是相当于我们重写load克拉方法,不采用双排机制可以吗?哎,注意可以对吧,那你相当于你把这个,哎二跟三的这个操作呢,我给它抹掉,那不就是体现不了双亲委派模型了吗。哎,这个是OK的啊,但是那我要是抹去了双性派机制,那是不是就意味着咱们可以用自定义的类的加载器啊,我可以呢去加载核心的API了呢,那你要能够加载核心API,那我核心API进行一个啊这个同名是吧的一个替换,那是不是就又可以了呢。
15:11
那注意这也不行,那这个是不行的啊,那这是因为JDK呢,还提供了核心这个类库的一个保护机制啊,不管你是自定义的还是系统类的,还是扩展类的啊,最终呢,咱们都要调用这个叫DeFine class。啊,就是在你这个find class里边调了一个DeFine class,而这个DeFine class里边呢,有一个叫pre啊class这样一个方法,这个方法里边那提供了对核心API类库的一个保护机制,仍然由引导类加载一起去实现。啊,这个具体来看的话呢,那我们打开一下这个class loader是吧。那拉在里边呢,咱们不是提到了这个叫呃,Load。哎,Class是吧,那class呢,调了一个方法来调它这呢核心的API,这不是咱们昨天就说的它,然后这里边呢,就调用了这叫DeFine,呃,调了一个find class find class里边啊find class,这个find class呢,这里注意咱们现在呢去调的话呢,对于class load来讲,它其实没有具体的填写这个方法体,方法体是为空的,对吧,那我们具体用的这个find class的话呢,咱们用的是谁呀。
16:20
咱们昨天前面呢讲的时候呢,看到的是不是URL,呃,Class,哎,Load是吧,掉的是它啊,然后在他这里边呢,他把这个final class呢进行了一个重写,在这个里边呢,它会去调用这个叫做DeFine class啊,在这呢是吧,这个DeFine class。啊,DeFine class,它这里边儿的话呢,就会调用咱们刚才提到的这样一个操作叫pre。哎,这个我们return它,哎,这又调到我们这个结构了是吧,我们再看一下它啊,这个里边又调它。啊,在这里边再进来,你看这有一个叫pre DeFine class啊,这个pre fun class,那就是我们刚才提到的,它是在class load里边定义的,是对我们核心API它的一个保护机制。
17:07
啊,这个注意啊,行,那知道了,咱们现在这说的什么问题就行,下面呢提道了叫双亲委派模型的一个弊端。啊,这是一个弊端,刚才呢,咱们提到了是咱们设计好的这个双节品牌这个模型,那这个模型呢,能不能打破呢?可以打破,使用这个load class方法的一个重写就可以了,对吧?好,那这个呃,可以打破,那这时候我们说为什么要打破,这就涉及到它的一个弊端问题了。啊,弊端问题我们看啊说呢,检查这个类啊,是否被加载的这个委托呀,咱们是单向的那层层往上对吧,这呢使得我们整个这个加载的职责呢,就非常的清晰,但是这样呢,带来问题就是顶层的就是上层的这个class o呢,无法访问这个底层的这个class o所加载的类。能理解这个问题吧,正常来讲呢,我们说,哎,比如说我们这有三层是吧,哎,依次往上啊,我们由这个类的加载器呢,它去加载某一个结构啊,它这个结构里边,比如又出现了另外的一个,呃,比如说这个我们自定义类里边出现了一个string啊,这个string要加载的话呢,呃,还得遵循这样一个逻辑,那层层往上,那在我们这个下层这块呢,我们通过这个自定义类的加载器,你想调用这个string是没问题的。
18:17
那就是底层可以调上层,但是呢,如果我们要是有上层的一些结构,它的具体的实现是由下层来完成的话呢,我们上层掉下层是不允许的。是不允许的,那我们在实际开发中呢,也确实有这样的诉求,比如说我们呢,提供了一个接口。啊,系统提供了一个接口是吧,那这个接口具体的实现呢,需要以我们这个具体的应用类啊应用类去实现,那咱们应该用系统类加载器去加载这个具体的应用类了,那或者的话呢,我们接口呢,它绑定了一个工厂方法,那由这个工厂方法呢,去实现接口的这个具体实例。但是呢,你现在这个呃,应用类也好,该接口的具体的实例也好,都得是有我们具体的系统类加载器啊,或者这块写的叫应用应用程序的这个啊,应用类的这个加载器,其实指的就是我们系统类加载器啊区进行加载了。
19:07
结果导致的问题就是我们这个,呃,上层的这个核心的系统的这些API,用的这个引导类加载器无法访问这个底层的这些实例。啊,这就麻烦了是吧,那这个结论是什么呢。结论的话呢,就是Java虚拟机啊,规范里边呃,没有明确说类的加载器的加载机制,说一定要使用双性源模型啊,建议大家这样使用而已。啊,相当于呢,是一个一个妥协或者叫折中的方案啊嗯,就好比是什么呢?比如说国家呢,现在咱们国家是吧,从这个宏观调控上来讲呢,这个要限制房价啊,习大大说了,这个房子是用来住的,对吧,不是用来炒的,不是用来投资的,好那就相当于给整个这个房市呢,是不是就做了一个基调,那就是这个不能炒房子,避免这个房价过高,对吧,这呢就类似于咱们说叫双亲委派模型。啊,这样一个模型,那很多城市,包括像北京啊,深圳,上海啊等等,都制定了非常严苛的这个限购的政策,是吧,像北京的话呢,你得满五年社保才允许你去买房子。
20:13
啊,那你要二套房子的话呢,这个首付的比例要很高,对吧,这都是一些限制措施,包括呢,在很多城市现在也出来这个叫啊房产税是吧?呃,房地产税,你要是房子太多的话呢,这个我给你征税啊,因为你要自己住,你咋可能住那么大面积的房子呢,对吧,还好好几套是吧,这个是不允许的啊,我就限制你,你有钱,有钱你就交税啊,是这种,那这呢是国家的宏观政策,但是呢,也看到一些地方,那比如说像现在这个东北那很多城市,大家不知道见没见过这个新闻说这个那四五万一套房子。对吧,四五万一套房子啊,这个还有人都都不买,那你要真的去住的话,那肯定会买对吧,但是你肯定不会去买对吧,那就是说地方呢,由于经济的一些原因,或者人流呃,人员外流的一些原因,导致当地这个房地产呢,整个呢,就是泡沫一下子就破了是吧,这个房价呢,跌的一塌糊涂,那这个时候呢,你就不能再去实施国家的这个限购政策了,你说首付的这个银行贷款利率还还挺高的,还上浮多少,那谁去买啊,那你对于这种场景下呢,我们就得是刺激这个,呃,老百姓呢去买房子是吧?哎,就是稳定房价,所以说对于国家这样一个大环境来讲呢,整体上来讲是限房啊限购的,那对于一些部分地区,那还有鼓励你去购房。
21:28
那这呢,就是一个不同是吧。那下边呢,你看也举了一个例子,你像像咱们这个Tom KD当中所采用的机制呢,跟传统的双星语派这个模型呢就不一样,它呢是先自己自行去加载,当他自己加载失败了,然后才交给他的超类,也就是说负类加载器呢再去加载。哎,这个呢,你看有点区别是吧,哎,行这呢,就是我们提到这个双性语派机制的这个优点和缺点啊,大家呢,需要熟悉这里边这个信息,包括呢,主要这个双性语派在代码中的哪个位置去体现的啊,这也要清楚。
我来说两句