【Java】浅谈ClassLoader类加载器

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.ClassLoaderloadClass方法中:

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;
        }
}

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值