JAVA类加载的委托模型

关于JAVA的类加载器,网上有很多这方面资料,这里只做测试,不多累述。JVM有三个内置加载器:           bootstrapClassLoader(由C语言编写,固化在jvm上)、ExtClassLoader、AppClassLoader。三个加载器从上到下呈父子关系,形成了“类加载委托模型”:即儿子的事情,父亲能做的,他一定会代劳(以免累到儿子),父亲的事情,一定会自已做,即使自已无法完成,也不会劳及儿子。三个类的加载路径分别为(更多细节参考google):

BootstrapClassLoader:    sun.boot.class.path 
ExtClassLoader:     java.ext.dirs                                                                                   AppClassLoader:     java.class.path

 

 首先定义两个类:

  
  
  
  
  1. package loader;  
  2.  
  3. public class ClassA {  
  4.    public static void main(String args[]){  
  5.        System.out.println("ClassA: " + ClassA.class.getClassLoader());  
  6.  ClassB a = new ClassB();  
  7.        System.out.println("ClassB: " + ClassA.class.getClassLoader());  
  8.    }  
  9. }  
  10. //
  11. package loader;  
  12.  
  13. public class ClassB {  

拷贝三份到:C:\Java\jre6\classes(bootstrapClassLoader的搜索目录之一),C:\Java\jre6\lib\ext\classes(extClassLoader的搜索目录之一),F:\javawork\study\bin目录下,其中C:\Java\jre6为我JRE目录。一定不要搞错,因为你的机器可能会有很多JRE。

CMD到F:\javawork\study\bin目录

1. F:\javawork\study\bin>java loader.ClassA
ClassA: null
ClassB: null

两个都为空,这是因为当AppClassLoader(默认的系统类加载器)来加载CLASSA,首先委托其父ExtClassLoader去加载,然后AppClassLoader委托bootstrapClassLoader去加载,bootstrapClassLoader没有父加载器,只能自已完成,在自已加载目录C:\Java\jre6\classes下找到了CLASSA,加载成功。然后CLASSA的加载器bootstrapClassLoader加载CLASSB,同样在C:\Java\jre6\classes找到CLASSB,所以两个类的加载器都是bootstrapClassLoader,因为bootstrapClassLoader实现于C++,所以返回NULL。

2. 删除C:\Java\jre6\classes目录下的CLASSB

F:\javawork\study\bin>java loader.ClassA
ClassA: null
Exception in thread "main" java.lang.NoClassDefFoundError: loader/ClassB
        at loader.ClassA.main(ClassA.java:6)

这是因为同(1)一样,最后由bootstrapClassLoader成功加载CLASSA,然后由CLASSA(这里叫CLASSB的CALLER)的加载器bootstrapClassLoader需要去加载CLASSB,但bootstrapClassLoader尽其力也没能找到(因为被我删了),这位慈爱的父亲到最后一刻都没有交给儿子ExtClassLoader去做,最后上报:我无能为力。

3.把(2)中删除的CLASSB还原,同时删创除该目录下的CLASSA

F:\javawork\study\bin>java loader.ClassA
ClassA: sun.misc.Launcher$ExtClassLoader@126b249
ClassB: null

两个都输出ExtClassLoader,顺着(1)的思路,AppClassLoader委托ExtClassLoader,ExtClassLoader委托bootstrapClassLoader,bootstrapClassLoader找不到CLASSA,只能放手让儿子去做(比如找女朋友这事,小伙子本来想老爸战友的女儿不错,可父亲去提亲,人家不应,“不行,儿子,你自个追其他的吧!”)。ExtClassLoader绝地逢生,在自已的区域内找到了CLASSA。然后CLASSA的加载器ExtClassLoader去加CLASSB, 同样道理这事交给老爸bootstrapClassLoader去做,bootstrapClassLoader责无旁贷,顺利完成,所以ClassB: null。

4.把(3)中剩下的CLASSB也删除。

 F:\javawork\study\bin>java loader.ClassA
ClassA: sun.misc.Launcher$ExtClassLoader@ad3ba4
ClassB: sun.misc.Launcher$ExtClassLoader@ad3ba4

同(1)一样,ExtClassLoader绝地逢生,在自已的区域内找到了CLASSA,然后CLASSA的加载器ExtClassLoader去加CLASSB,不幸的事,这次老爸bootstrapClassLoader却无能为力(被我CUT了)。最后ExtClassLoader自已搞定。

5.继序(4)删除C:\Java\jre6\lib\ext\classes目录下的CLASSB

F:\javawork\study\bin>java loader.ClassA
ClassA: sun.misc.Launcher$ExtClassLoader@126b249
Exception in thread "main" java.lang.NoClassDefFoundError: loader/ClassB
        at loader.ClassA.main(ClassA.java:6)

按上面的思路,你一定知道为什么。

6.还原(5)中删除的CLASSB,同时删除CLASSA.

F:\javawork\study\bin>java loader.ClassA
ClassA: sun.misc.Launcher$AppClassLoader@ad3ba4
ClassB: sun.misc.Launcher$ExtClassLoader@126b249

AppClassLoader(默认的系统类加载器)来加载CLASSA,首先委托其父ExtClassLoader去加载,然后AppClassLoader委托bootstrapClassLoader去加载.可两们前辈都无能为力,最后还是落到了AppClassLoader身上,少年英雄很快实现自已的梦想,成功加载CLASSA,然后其CLASSA的加载器(还是AppClassLoader)再去加载CLASSB,喜出望外的是,老爸ExtClassLoader代其完成,大功告成。

7.继序(6)删除C:\Java\jre6\lib\ext\classes目录下的CLASSB 

F:\javawork\study\bin>java loader.ClassA
ClassA: sun.misc.Launcher$AppClassLoader@ad3ba4
ClassB: sun.misc.Launcher$AppClassLoader@ad3ba4

同样道理,委托,委托。但这次AppClassLoader在我的破坏下(我删,删),只能自力更生。完成加载。

有一点问题,在测试过程中我的本机并没有CLASSPATH变量:

F:\javawork\study\bin>set classpath
环境变量 classpath 没有定义

但System.out.println(System.getProperty("java.class.path")) 输出:. 即当前目录作为了classpath.

你可能感兴趣的:(java,职场,休闲)