Java 中的类加载器大致可以分成两类,一类是系统提供的,另外一类则是由 Java 应用开发人员编写的。系统提供的类加载器主要有下面三个:
引导类加载器(bootstrap class loader)
用来加载 Java 的核心库,是用原生代码 C++ 实现,在 java 里无法获取,并不继承自 java.lang.ClassLoader。主要负责 jdk_home/lib 目录下的核心 api 或 -Xbootclasspath 选项指定的 jar 包装入工作(其中的 jdk_home 是指配置 jdk 环境变量是 java_home 的配置路径,一般是 jdk/jre 所在目录)。
扩展类加载器(extensions class loader)
Java实现,可以在java里获取。它用来加载 Java 的扩展库。Java 虚拟机的实现会提供一个扩展库目录,扩展类加载器在此目录里面查找并加载 Java 类,主要负责 jdk_home/lib/ext 目录下的 jar 包或 -Djava.ext.dirs 指定目录下的 jar 包装入工作。
系统类加载器(system class loader)
它根据 Java 应用的类路径(CLASSPATH)来加载 Java 类。一般来说,Java 应用的类都是由它来完成加载的。可以通过 ClassLoader.getSystemClassLoader()
来获取它。主要负责 CLASSPATH/-Djava.class.path 所指的目录下的类与 jar 包装入工作。
除了系统提供的类加载器以外,开发人员可以通过继承 java.lang.ClassLoader 类的方式实现自己的类加载器,从而进行动态加载 class 文件,以满足一些特殊的需求,这体现 java 动态实时类装入特性。
除了引导类加载器之外,所有的类加载器都有一个父类加载器,通过 getParent() 方法可以得到。对于系统提供的类加载器来说,系统类加载器的父类加载器是扩展类加载器,而扩展类加载器的父类加载器是引导类加载器;对于开发人员编写的类加载器来说,其父类加载器是加载此类加载器 Java 类的类加载器。因为类加载器 Java 类如同其它的 Java 类一样,也是要由类加载器来加载的。一般来说,开发人员编写的类加载器的父类加载器是系统类加载器。类加载器通过这种方式组织起来,形成树状结构。树的根节点就是引导类加载器。下图中给出了一个典型的类加载器树状组织结构示意图,其中的箭头指向的是父类加载器。
双亲委派
如果一个类加载器收到了加载某个类的请求,则该类加载器并不会去加载该类,而是把这个请求委派给父类加载器,每个层次的类加载器都是如此,因此所有的类加载请求最终都会传送到顶端的引导类加载器。
只有父类加载器在其搜索范围内无法找到所需的类,并将该结果反馈给子类加载器,子类加载器才会尝试去加载。