类加载器负责加载Java类的字节代码到Java虚拟机中。
类加载器使得Java类可以被动态加载到JVM中并执行。一般情况下Java应用的开发人员不需要直接通类加载器进行交互,JVM默认的行为就已经足够满足大多数情况的需求了,不过当需要与类加载器进行交互时,如果使用不当就很容易出现ClassNotFoundException和NoClassDefFoundError等异常。
1、基本概念
类加载器(class loader)用来加载Java类到JVM中。一般来说,Java虚拟机使用Java类的方式如下:Java源程序(.java文件)在经过Java编译器编译之后就被转换成Java字节代码(.class文件)。类加载器负责读取Java字节代码,并转换成java.lang.Class类的一个实例。这样每个实例都表示一个Java类。通过此实例的newInstance()方法就可以创建出该类的一个对象。实际情况可能更加复杂,比如Java字节代码可能是通过工具动态生成,也可能是通过网络下载的。
基本上所有的类加载器都是Java.lang.ClassLoader类的一个实例。
java.lang.ClassLoader类的基本职责就是根据一个指定的类的名称,找到或者生成其对应的字节代码,然后从这些字节代码中定义出一个实例。除此之外,ClassLoader还负责加载java应用所需的资源,如图像和配置文件等。
2、类加载器的树状组织结构
java中的类加载器大致可以分为两类,一类是系统提供的,另一类是有java应用开发人员编写的。系统提供的类加载器主要有下面三个:
引导类加载器(bootstrap class loader):它用来加载java的核心库,是用原来代码实现的,并不继承自java.lang.ClassLoader。
扩展类加载器(extension class loader):它用来加载java的扩展库,java虚拟机的实现会提供一个扩展库目录。该类加载器在此目录里面查找并加载java类。
系统类加载器(system class loader):它根据java应用的类路径(CLASSPATH)来加载java类。一般来说,java应用的类都是由它来完成加载的。可以通过ClassLoader.getSystemClassLoader()来获取它。
除了系统提供的类加载器外,开发人员可以通过集成java.lang.ClassLoader类的方式实现自己的类加载器,以满足一些特殊的需求。除了引导类加载器以外,所有的类加载器都有一个父类加载器,可以通过getParent()方法得到。对于系统提供的类加载器来说,系统加载器的父类加载器是扩展类加载器,而扩展类加载器的父类加载器是引导类加载器,对于开发人员编写的类加载器来说,其父类加载器是加载此类加载器java类的类加载器。因为类加载器java类如同其他的java类一样,也是要有类加载器来加载的。一般来说,开发人员编写的类加载器的父类加载器是系统类加载器。其树形结构如下:
清单1.演示类加载器的树状组织结构
public class ClassLoaderTree {
public static void main(String[] args) {
ClassLoader loader = ClassLoaderTree.class.getClassLoader();
while (loader != null) {
System.out.println(loader.toString());
loader = loader.getParent();
}
}
}
每个java类都维护者一个指向定义它的类加载器的引用,通过getClassLoader()方法就可以获取到此引用。同时在清单1中,利用递归调用getParent()方法来输出全部的父类加载器。