再论java反射之Classloader

                            返回主页

类加载器

类加载器的职责就是载入.class文档,JDK本身有默认的类加载器。也可以建立自己的类加载器加入现有的加载器层级。

类加载器层级结构

执行java xxx命令之后,java执行程序会尝试寻找JRE安装目录,然后寻找JVM;

接着启动JVM并初始化动作,然后产生Bootstrap Loader,

Bootstrap Loader会产生Extended Loader,并将Extended Loader的父加载器设置为Bootstrap Loader,

接着Bootstrap Loader产生System Loader,并将System Loader的父加载器设为Extended Loader。

注意

. Bootstrap Loader通常由C语言写成,在Java中没有实际的类实例对应; . Extended Loader、System Loader由java写成;

类加载顺序

在加载类时,每个类加载器会先将加载类的任务交给父加载器,如果父加载器找不到则由自己进行加载。所以加载指定类时,会以如下顺序进行:

Bootstrap Loader -> Extended Loader -> System Loader

如果所有的类加载器都找不到指定类,就会抛出java.lang.NoClassDefFoundError

关于父ClassLoader实例

类加载器都继承自抽象类java.lang.ClassLoader。

每个.class文件加载之后,都会有一个Class实例来代表,可以由Class的getClassLoader()取得加载对应.class文档的ClassLoader实例;

而ClassLoader的getParent()方法可以取得父ClassLoader实例;

代码实例

package Refection;

public class Some {
    /*ClassLoader可以使用loadClass()加载类,
但是静态块默认不会执行,只有在真正建立类的实例时才会执行类的静态区块;*/
    static {
        System.out.println("载入some.class文档(static块)");
    }
}

package classloader;

import Refection.Some;

public class ClassLoader {

    public static void main(String[] args) {
        Some some = new Some();//生成Some实例
        Class clz = some.getClass();//取得Some.class的Class实例
        java.lang.ClassLoader loader = clz.getClassLoader();//取得classloader
        System.out.println(loader);
        System.out.println(loader.getParent());
        System.out.println(loader.getParent().getParent());
    }
}

 运行结果

sun.misc.Launcher$AppClassLoader@4e0e2f2a
sun.misc.Launcher$ExtClassLoader@2a139a55
null

解释

AppClassLoader即为System ClassLoader

出现**null**的原因是由于loader.getParent().getParent()得到的结果为Extended loader的父加载器即Bootstrap Loader,
在前面已经提到Bootstrap Loader由C撰写,在Java中没有对应的实例
表示,因此显示为null;

补充

由同一个类加载器载入的.class文档只有一个Class实例。

如果同一个.class文档由两个不同的类加载器加载,则会有两个不同的类实例;

PS:如果在程序的运行过程中,打算动态决定从其他类路径加载类,就要产生新的类加载器(自定义类加载器);新的类加载器建立之后,父类加载器会设置为System Loader.

关于双亲委派机制

双亲委派模型工作流程为:如果一个类加载器收到了类加载的请求,
它不会首先尝试自己去加载这个类,而是会把这个请求委派给父类加载器去完成

每一个层次的加载器都是如此,因此所有的加载请求都应该传送到顶层的启动类加载器(Bootstrap Loader).只有当父类加载器反馈自己无法完成加载请求时,子加载器才会尝试自己去加载这个类。(摘自《深入理解Java虚拟机》)