ClassLoader 深入解析 (三)

2014-11-24 01:25:06 · 作者: · 浏览: 1
中设定好加载.class 文件的路径可以实现自定义的加载机制。

假设我们已经定义好自己的加载器MyClassLoader,我们使用如下的代码便能够构造出例子中的类加载器树形结构。

MyClassLoader loadB = new MyClassLoader(“loadB”);

loadB.setPath(“D://app//serverlib”);

MyClassLoader loadA = new MyClassLoader(loadB,“loadA”);

loadB.setPath(“D://app//cientlib”);

MyClassLoader loadC = new MyClassLoader(null,”loadC”)//null代表父加载器为Bootstrap

loadC.setPath(“D://app//otherlib”);

我们一个测试类Sample 和一个测试类Dog进行加载测试。

Class Sample{

Static{

New Dog();

}

}


Class文件的存放路径如下:

d:app/syslib/MyClassLoader.class

d:app/serverlib/Sample.class

d:app/clientlib/Dog.class

d:app/otherlib/Sample.class,Dog.class


TestCase1 :

Class clazz = loadA.loadClass(“Sample”);

Clazz.newInstance();

TestCase2 :

Class clazz = loadB.loadClass(“Sample”);

Clazz.newInstance();

TestCase3 :

Class clazz = loadC.loadClass(“Sample”);

Clazz.newInstance();

在case1 中 由加载器的树形结构可以看出:loadA加载Sample时委托父亲LoadB加载Sample,由于再向上委托并不能加载Sample,所以 Sample 由LoadB在 app/serverlib 下加载,

对于Dog类,LoadA的所有父加载器都不能加载,所以有loadA在 app/clientlib下加载

在case2 中 有loadB在 app/serverlib中加载 Sample,由于loadB 与其父加载器都不能加载Dog,所以会抛出ClassNotfoundException。此时如果把Dog拷贝到 syslib下,Dog类就会被appCloader加载,而不会出现ClassNotFound错误。

在Case3 中LoadC直接委托Bootstrap加载Sample,由于无法加载只能有自己加载,所以Sample 与Dog都会从 app/otherlib/下加载.

假设 我们在MyClassLoader中写意给main方法测试

TestCase4 :

Class clazz = loadA.loadClass(“Sample”);

Sample sample = Clazz.newInstance();

此时会导致一个NoClassDefError,这主要是JVM的类加载器命名空间规则导致的,在jvm中子加载器的命令空间包含了父加载器加载的所有类,反过来则不成立,因为MyClassLoader类是有appLoader加载的,所以其看不见有LoadB与loadA加载的类。

在这里顺便提一下,在一个类主动使用时,该类就开始起生命周期 加载,链接,初始化,使用,卸载。Jvm自带的加载器加载的Class是不能够被卸载的,只有用户自定义加载器加载的类才能被卸载,卸载机制是根据对类的引用计数情况而定,这与GC根据引用情况回收垃圾差不多