在对ExtClassLoader getParent()的时候,会抛出NullPointException. Class是在需要使用的时候才被系统加载,而ClassLoader是用来加载Class的,一共有三种默认ClassLoader:
- Bootstrap loader
- ExtClassLoader
- AppClassLoader
Bootstrap loader是由C写成,而后两者由Java写成。在Java程序启动的时候,会依次按照以上排列顺序加载class loader, 并把上一个classloader设为自己的parent. 具体如下图:
默认情况下,各个classloader会在如下目录搜索class并加载:
- Bootstrap loader: sun.boot.class.path中指定位置的類別,預設是JRE所在目錄的classes下之.class檔案,或lib目錄下.jar檔案中(例如rt.jar)
- ExtClassLoader: java.ext.dirs中 指定位置的類別,預設是JRE目錄下的lib\ext\classes目錄下的.class檔案,或lib\ext目錄下的.jar檔案
- AppClassLoader: classpath 指向的目录下的class或者jar包
在加载的时候,每个classloader都会先把加载的优先权交给其“父classloader”,只有在“父classloader”找不到资 源的情况下才让给下一级别的classloader加载。对每个Class对象,我们可以用getClassLoader()来得到加载这个Class的 ClassLoader,对每个classloader也可以用getParent()来得到父级别的ClassLoader
这里要注意Bootstrap是C写的,没有对应的java object,所以:
- 在对ExtClassLoader getParent()的时候,会抛出NullPointException.
- 当我们把Class文件放在JRE目录的classes目录下,拿这个Class的ClassLoader的时候只会拿到NULL.
我们可以利用URLClassLoader类来自定义ClassLoader,
URL url = new URL("file:/d:/workspace/");
ClassLoader urlClassLoader = new URLClassLoader(new URL[] {url});
Class c = urlClassLoader.loadClass("SomeClass");
loader会自动成为AppClassLoader的子Loader。当我们用两个自定义loader加载class的时候,这个class如果是在上级AppClassLoader的目录被找到,则只有一个对象生成。 如果是各自的自定义loader找到,则会生成2个对象。
此文基于以下两篇文章: