Java类加载器负责加载所有的类,系统会为所有被载入内存的类生成一个java.lang.Class实例。对于同一个类,一旦被加载如内存中,就不会被再次加载。JVM使用一个类的权限的类名和该类的加载器唯一地标识一个类。因此即使两个类的包名、类名完全相同,但是使用不同的类加载器加载,这两个类也会被认为是不同的。 当程序首次使用某个类时,如果该类还未被加载,则系统会通过以下三个步骤加载该类:
有时,也将上述三个步骤统称为类的加载。
当JVM启动时,会形成由三个类加载器组成的初始化类加载器层次结构:
三个类加载器之间存在父子层级关系,即Bootstrap ClassLoader是Extension ClassLoader的父类加载器,Extension ClassLoader是Application ClassLoader的父类加载器。这里类加载器的父子关系一般不会以继承(Inheritance)的关系来实现,而是都使用组合(Composition)关系来复用父加载器的代码。 默认情况下,Java程序使用Application ClassLoader加载一个类。示例程序如下:
public class CLassLoaderTest {
public static void main(String[] args) {
//获取当前线程下的ClassLoader
ClassLoader current = Thread.currentThread().getContextClassLoader();
System.out.println("current:" + current);
//获取父类加载器
System.out.println("parent:" + current.getParent());
System.out.println("grandparent:" + current.getParent().getParent());
}
}
输出结果:
current:sun.misc.Launcher$AppClassLoader@56e88e24
parent:sun.misc.Launcher$ExtClassLoader@3dcc0a0f
grandparent:null
由此可见,Java程序默认采用Application ClassLoader,Extension ClassLoader为Application ClassLoader的父类加载器。由于Bootstrap CLassLoader由C++编写,在程序中无法获取,所以返回null。
JVM采用如下三种类加载机制:
为了更好地说明JVM的类加载机制,对ClassLoader的loadClass()方法的源码分析如下:
protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
synchronized (getClassLoadingLock(name)) {
//首先,检查该类是否已经被加载,如果已经加载过,则直接返回该Class(缓存机制)
Class c = findLoadedClass(name);
if (c == null) {
long t0 = System.nanoTime();
try {
//如果该类未被加载,首先尝试获取父加载器,如果父加载器不为null,则使用父加载器进行加载(父类委托机制)
if (parent != null) {
c = parent.loadClass(name, false);
} else {
//如果父加载器为空,说明当前加载器为ExtensionClassLoader 或 BootstrapCLassLoader,则使用根类加载器进行加载
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
//如果使用根类加载器加载失败,则抛出 ClassNotFoundException
}
if (c == null) {
//如果父加载器未能成功加载,则使用当前的类加载器进行加载
long t1 = System.nanoTime();
c = findClass(name);
sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
sun.misc.PerfCounter.getFindClasses().increment();
}
}
if (resolve) {
resolveClass(c);
}
return c;
}
}