ClassLoader是用来加载类到Java虚拟机中的一种加载器。它将 Class 的字节码形式转换成内存形式的 Class 对象 。
public final class Class<T> implements java.io.Serializable,
GenericDeclaration,
Type,
AnnotatedElement {
...
/*
* Private constructor. Only the Java Virtual Machine creates Class objects.
* This constructor is not used and prevents the default constructor being
* generated.
*/
private Class(ClassLoader loader) {
// Initialize final field for classLoader. The initialization value of non-null
// prevents future JIT optimizations from assuming this final field is null.
classLoader = loader;
}
查看class的源码可以发现,每个 Class 对象的内部都有一个 classLoader 字段来标识自己是由哪个 ClassLoader 加载的。
在JVM中,执行代码时并不是一次性加载全部所需的类,即延迟加载。程序在运行的过程中调用 ClassLoader 来加载运行时所遇到的类,并将 Class 对象存在 ClassLoader 中,以后无需重新加载。在初始化阶段,使用new关键字实例化对象、或者调用某个类的静态方法时,都会首先加载这个类;在反射机制中,类需要初始化(Class.forName()方法);类初始化时,需要先初始化其父类(双亲委派)。
每一个类加载器都有一个独立的命名空间,所以每一个类,都要由它的类加载器和类本身来在JVM中加载,并保存在内存中。比较两个类是否“相等”需要比较类对象的equals()、isAssignableFrom()、isInstance()方法的返回值,只有被同一个类加载器加载的类。
双亲委派模式
首先我们可以看到每个ClassLoader对象都会有一个parent属性来指向它的父加载器。
public abstract class ClassLoader {
private static native void registerNatives();
static {
registerNatives();
}
// The parent class loader for delegation
// Note: VM hardcoded the offset of this field, thus all new fields
// must be added *after* it.
private final ClassLoader parent;
在ClassLoader的源码中可以看到,ClassLoader使用的是双亲委派来搜索加载类的,每个ClassLoader实例都有一个父类加载器的引用,虚拟机内置的类加载器(Bootstrap ClassLoader)是最上层的类加载器(没有父类加载器)。当一个ClassLoader实例需要加载某个类时,它会先把这个任务委托给它的父类加载器,从顶层的Bootstrap ClassLoader自上至下依次检查(Bootstrap ClassLoader -> Extension ClassLoader -> Application ClassLoader),如果它们都没有加载到这个类时,则抛出ClassNotFoundException异常,再调用自定义加载器的findClass()加载。
下面是双亲委派模式的源码,集中于java.lang.ClassLoader的loadClass方法中:
protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
synchronized (getClassLoadingLock(name)) {
// First, check if the class has already been loaded
Class<?> c = findLoadedClass(name);
if (c == null) {
long t0 = System.nanoTime();
try {
if (parent != null) {
c = parent.loadClass(name, false);
} else {
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
// ClassNotFoundException thrown if class not found
// from the non-null parent class loader
}
if (c == null) {
// If still not found, then invoke findClass in order
// to find the class.
long t1 = System.nanoTime();
c = findClass(name);
// this is the defining class loader; record the stats
sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
sun.misc.PerfCounter.getFindClasses().increment();
}
}
if (resolve) {
resolveClass(c);
}
return c;
}
}