关于JAVA的类加载器,网上有很多这方面资料,这里只做测试,不多累述。JVM有三个内置加载器: bootstrapClassLoader(由C语言编写,固化在jvm上)、ExtClassLoader、AppClassLoader。三个加载器从上到下呈父子关系,形成了“类加载委托模型”:即儿子的事情,父亲能做的,他一定会代劳(以免累到儿子),父亲的事情,一定会自已做,即使自已无法完成,也不会劳及儿子。三个类的加载路径分别为(更多细节参考google):
BootstrapClassLoader: sun.boot.class.path
ExtClassLoader: java.ext.dirs AppClassLoader: java.class.path
首先定义两个类:
- package loader;
- public class ClassA {
- public static void main(String args[]){
- System.out.println("ClassA: " + ClassA.class.getClassLoader());
- ClassB a = new ClassB();
- System.out.println("ClassB: " + ClassA.class.getClassLoader());
- }
- }
- //
- package loader;
- 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.