Java ClassLoader详解

Java ClassLoader笔记

Java语言系统自带有三个类加载器

Bootstrap ClassLoader 最顶层的加载类,主要加载核心类库,%JRE_HOME%\lib下的rt.jar、resources.jar、charsets.jar和class等。另外需要注意的是可以通过启动jvm时指定-Xbootclasspath和路径来改变Bootstrap ClassLoader的加载目录。比如java -Xbootclasspath/a:path被指定的文件追加到默认的bootstrap路径中。
Extention ClassLoader 扩展的类加载器,加载目录%JRE_HOME%\lib\ext目录下的jar包和class文件。还可以加载-D java.ext.dirs选项指定的目录。 
Appclass Loader也称为SystemAppClass 加载当前应用的classpath的所有类。

下面是测试BootStrap ClassLoader加载的哪些文件:

/**
 * BootStrap ClassLoader 加载的文件
 */
public class Test {
    public static void main(String[] args)throws  Exception{
        System.out.println(System.getProperty("sun.boot.class.path"));
    }
}
123456789

输出:

C:\Program Files\Java\jre1.8.0_151\lib\resources.jar;
C:\Program Files\Java\jre1.8.0_151\lib\rt.jar;
C:\Program Files\Java\jre1.8.0_151\lib\sunrsasign.jar;
C:\Program Files\Java\jre1.8.0_151\lib\jsse.jar;
C:\Program Files\Java\jre1.8.0_151\lib\jce.jar;
C:\Program Files\Java\jre1.8.0_151\lib\charsets.jar;
C:\Program Files\Java\jre1.8.0_151\lib\jfr.jar;
C:\Program Files\Java\jre1.8.0_151\classes

下面是测试Extention ClassLoader加载的哪些文件:

/**
 * EtxClassLoader 加载文件
 */
public class Test {
    public static void main(String[] args)throws  Exception{
        System.out.println(System.getProperty("java.ext.dirs"));
    }
}12345678

输出:

C:\Program Files\Java\jre1.8.0_91\lib\ext;

ClassLoader源码

protected Class<?> loadClass(String name, boolean resolve)
    throws ClassNotFoundException
{
    synchronized (getClassLoadingLock(name)) {
        // 首先查找该加载器是否已经加载了所要加载类
        Class<?> c = findLoadedClass(name);
        if (c == null) {
            long t0 = System.nanoTime();
            try {
                // 如果父加载器不为空就递归调用loadClass,如果父加载器为空就会调用BootstrapLoader,这也说明ExtentionClassLoader的父加载器为null还可以委托BootstrapLoader来加载的原因
                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();
                // 默认情况下,这个方法实际是在上面说有类加载器都无法找到所要加载类时,抛出异常,throw new ClassNotFoundException(name);
                // 也可以自定义ClassLoader覆盖该方法去继续查找所要加载类
                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;
    }
}

补充

同一个加载器加载的同源类才是真的同类。不同加载器加载同源类,不是同类!instanceof为FALSE;

Class.forName和ClassLoader.loadClass的区别

// 或者可以用 ClassLoader loader = ClassLoader.getSystemClassLoader();
ClassLoader loader = Thread.currentThread.getContextClassLoader(); 
//这句话没有执行初始化,其实与Class.forName("xx.xx",false,loader)是一致的,只是loader.loadClass("xx.xx")执行的是更底层的操作
Class cls = loader.loadClass("xx.xx"); 
// 执行这句才进行初始化
cls.NewInstance()

补充

  • 是否被初始化

    Class.forName(className) 实际上是调用Class.forName(className, true, this.getClass().getClassLoader()。注意第二个参数,是指Class被loading后是不是必须被初始化。 ClassLoader.loadClass(className)实际上调用的是ClassLoader.loadClass(name, false),第二个参数指出Class是否被link。 区别就出来了。Class.forName(className)装载的class已经被初始化,而ClassLoader.loadClass(className)装载的class还没有被link。

  • forName支持数组类型,loadClass不支持数组

    一般情况下,这两个方法效果一样,都能装载Class。但如果程序依赖于Class是否被初始化,就必须用Class.forName(name)了。 例如,在JDBC编程中,常看到这样的用法,Class.forName(“com.mysql.jdbc.Driver”),如果换成了 getClass().getClassLoader().loadClass(“com.mysql.jdbc.Driver”),就不行。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一只努力的微服务

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值