大可制作:QQ群:31564239(asp|jsp|php|mysql)

Java Gossip: 简介 ClassLoader

Java在需要使用类的时候,才会将类载入,Java的类载入是由类载入器(Class loader)来达到的,默认上,在程序启动之后,主要会有三个类载入器:Bootstrap Loader、ExtClassLoader与AppClassLoader

Bootstrap Loader是由C++撰写而成,默认上它负责搜寻JRE所在目录的classes或lib目录下的.jar文件中(例如rt.jar)是否有指定的类并载入(实际上是由系统参数sun.boot.class.path指定);默认上ExtClassLoader负责搜寻JRE所在目录的lib/ext 目录下的classes或.jar中是否有指定的类并载入(实际上是由系统参数java.ext.dirs指定);AppClassLoader则搜寻 Classpath中是否有指定的classes并载入(由系统参数java.class.path指定)。

Bootstrap Loader会在JVM启动之后载入,之后它会载入ExtClassLoader并将ExtClassLoader的parent设为Bootstrap Loader,然后BootstrapLoader再载入AppClassLoader,并将AppClassLoader的parent设定为 ExtClassLoader。

在载入类时,每个类载入器会先将载入类的任务交由其parent,如果parent找不到,才由自己负责载入,如果自己也找不到,就会丢出 NoClassDefFoundError

每一个类被载入后,都会有一个Class的实例来代表它,每个Class的实例都会记得是哪个ClassLoader载入它的,可以由Class的getClassLoader()取得载入该类的ClassLoader。

来撰写一个简单的程序测试类载入器,首先写一个测试类:

  • ClassLoaderTest.java
public class ClassLoaderTest {
static {
System.out.println("类被载入...");
}
}

将这个类先放在Classpath的路径下,然后撰写以下的程序:
  • ClassPathDemo.java
public class ClassLoaderDemo {
public static void main(String[] args) {
ClassLoaderTest test = new ClassLoaderTest();

ClassLoader loader =
test.getClass().getClassLoader();

System.out.println(loader);
System.out.println(loader.getParent());
System.out.println(loader.getParent().getParent());
}
}

执行程序之后,会出现以下的讯息:   
类被载入...
sun.misc.Launcher$AppClassLoader@82ba41
sun.misc.Launcher$ExtClassLoader@923e30
null


这表示ClassLoaderTest类是由sun.misc.Launcher产生的AppClassLoader所载入,而 AppClassLoader的parent是ExtClassLoader(AppClassLoader与ExtClassLoader都是内部类 别),ExtClassLoader的parent则是Bootstrap Loader,最后一个显示null并不是表示没有ClassLoader,而是因为Bootstrap Loader是由C++撰写而成,在Java中并没有一个实际代表它的类,因而没有类实例来表示Bootstrap Loader。

如果把ClassLoaderTest的class文件放到JRE目录下的lib/ext/classes下,并重新执行程序,您会看到以下的讯息:

类被载入...
sun.misc.Launcher$ExtClassLoader@923e30
null
Exception in thread "main" java.lang.NullPointerException
        at ClassLoaderDemo.main(ClassLoaderDemo.java:9)


 
这次ClassLoaderTest是由ExtClassLoader找到了,由于Bootstrap Loader并没有代表它的实例,所以是null,因而最后一行试图再使用getParent()时会出现NullPointException。

如果您将ClassLoaderTest的class文件移至JRE目录下的classes目录下,执行程序的话会出现以下的讯息:

类被载入...
null
Exception in thread "main" java.lang.NullPointerException
        at ClassLoaderDemo.main(ClassLoaderDemo.java:8)


出现null讯息,表示这次ClassLoaderTest是由Bootstrap Loader载入的。

这边只是对类载入器作个简单的描述,想更深入了解类载入器,可引用这篇 深入类载入器