类加载的父亲委托机制

咱们都知道。类加载器用来把类加载到java虚拟机。从JDK2.0开始,类的加载过程采用父亲委托机制。JVMClassLoader采用的是树形结构,除了根类加载器之外,每一个ClassLoader都会有且仅有一个父类加载器,用户自定义的ClassLoader默认的父类加载器是系统类加载器,固然你能够本身指定须要用个ClassLoader的实例,咱们来看他们的父子关系:java

父类委托机制中,当一个java程序请求加载器loader1加载Hello类时,loader1首先委托本身的父亲加载器加载hello类,若父亲加载器能加载,则由附加器完成加载人物,不然才由加载器loader1自己加载Hello类。下面咱们来再次看一下java虚拟机自带的几个加载器:安全

除了java虚拟机自带的加载器以外,咱们用户本身也能够自定义本身的类加载器,根据本身的须要。。Java提供了抽象类java.lang.ClassLoder,全部用户自定义的类加载器都要继承这个classloader类。spa

注:加载器之间的父子关系实际上指的是加载器对象之间的包装关系,而不是类之间的继承关系。一对父子加载器多是同一个加载器类的两个实例,也可能不是。在子加载器对象中包装了一个父加载器对象.当生成一个自定义的类加载器实例时,若是没有指定它的父加载器,那么系统类加载器就将成为该类加载器的父加载器。若是在构造方法中指定父类加载器那么父类加载器就是指定的加载器。证实以下:
code


ClassLoader loader1 = new MyClassLoader();
//参数loader1将做为loader2的父加载器
ClassLoader loader2 = new MyClassLoader(loader1);

Java虚拟机要加载一个类时,到底该派哪一个类加载器去加载呢?咱们看下图:orm

loader1loader2是咱们本身定义的两个类加载器,loader1loader2是父子关系。如今咱们想让loader2这个类加载器加载咱们本身写的一个Sample类:对象

loader2.loadclass("sample");

咱们来分析一下看看到底应该用哪个类加载器去加载。当这段代码被执行时,loader2首先到本身的命名空间去查找Sample类是否已经被加载,若是被加载就直接返回这个类的class对象的引用。若是Sample类尚未被加载,loader2首先请求loader1代为加载,loader1再请求系统类加载器代为加载,系统类加载器再请求扩展类加载器,扩展类加载器再请求根类加载器,若根类加载器和扩展类加载器都不能加载,则系统类加载器尝试加载,若能加载,则将Sample类所对应的Class对象的引用返回给loader1loader1在将引用返回给loader2,从而成功将Sample类加载到虚拟机。若系统类加载器不能加载Sample类,则loader1尝试加载Sample了哦,若loader1不能加载,则loader2尝试,若全部的类加载都不能加载,则抛出ClassNotFoundException异常。
继承

定义类加载器:若是某个类加载器可以加载一个类,那么该类加载器就称做:定义类加载器;定义类加载器及其全部子加载器都称做:初始类加载器ssl


父委托机制的优势就是可以提升软件系统的安全性。由于在词机制下,用户自定义的类加载器不可能加载本应该由父加载器加载的可靠类,从而防止不可靠的恶意代码代替由父类加载器加载的可靠类,从而防止不可靠的甚至恶意的代码代替由父类加载器加载的可靠代码。如,java.lang.Object类老是由根类加载器加载的,其余任何用户自定义的类加载器都不可能加载含有恶意代码的java.lang.Object类。 虚拟机


命名空间,其实这里所说的命名空间就是咱们java中经常使用的package,每一个类加载器都有本身的命名空间,命名空间由该加载器及全部父加载器所加载的类的组成。在同一个命名空间中,不会出现类的完整名字(包括类的包名)相同的两个;在不一样的命名空间中,有可能会出现类的完整名字(包括类的包名)相同的两个类。
it


由同一类加载器加载的属于相同包的类组成了运行时包。决定两个类是否是属于同一个运行时包,不只要看他们的包名称是否相同,还要看定义类加载器是否相同。只有属于同一运行时包的类之间才能相互访问可见(默认访问级别)的类和成员。假设用户自定义了一个类java.lang.TestCase并由用于自定义的类加载器加载,因为java.lang.TestCase和核心类库java.lang.*由不一样的类加载器加载,他们属于不一样的运行时包,因此java.lang.TestCase不能访问核心库java.lang包中的包可见成员。

相关文章
相关标签/搜索