Java体系中定义了3中类加载器,分别如下:
- Bootstrap ClassLoader(引导类加载器).负责加载下述3中情况下所制定的核心类库:
- %JAVA_HOME%/jre/lib目录
- -Xbootclasspath 参数所指定的目录
- 系统属性sun.boot.class.path指定的目录中特定名称的jar包
- Extension ClassLoader(扩展类加载器) 加载扩展类,拓展JVM的类库
- %JAVA_HOME%/jre/lib/ext目录
- 系统属性java.ext.dirs所指定的目录中的所有类库
- System ClassLoader(系统类加载器) 加载Java应用程序类库,加载类库的路径由系统环境变量ClassPath、-cp或系统属性java.class.path指定
-
图中各类加载器之间的关系,并非Java类面向对象的三大特性之一的那种“继承”关系。毕竟引导类加载器是使用C++语言编写而成的,Java类编写的类加载器想去继承也无法继承。
- 图中所表达的关系,仅仅是类的委托加载机制,尤其是著名的“双亲委派”。虽然几种加载器之间没有继承关系,但是扩展类加载器及用户自定义加载器,却都继承自java.lang.ClassLoader这个基类。
- 图中所表达的委托关系,本质上通过java.lang.ClassLoader.parent字段实现,该字段表示父加载器。对于引导类加载器,并没有所谓的父加载器的概念,因为引导类加载器本身是随JVM的启动而初始化,并且该类中的字段和方法全部是静态字段和方法,并不需要实例化便能使用。而除了引导类加载器之外的所有类加载器,由于都继承自java.lang.ClassLoader这个基类,因此便都有parent字段,由于该字段被final private 修饰,因此子类只能通过调用java.lang.ClassLoader的构造函数才能初始化该字段。对于扩展类加载器和系统类加载器,在JVM第一次加载Java类时会被创建,并完成其父类加载器的设定。扩展类加载器与系统类加载器在sun.misc.Launcher类的构造函数中完成初始化,sun.misc.Launcher类的构造函数逻辑如下:
-
在Launcher类的构造函数中,首先创建了扩展类加载器,接着创建了系统类加载器。注意,扩展类加载器是在构造函数中定了的局部变量ext1,而系统类加载器则是Launcher类的成员变量loader。但是当Launcher类的构造函数执行完之后,扩展类加载器实例对象并不会被GC回收,因为在创建系统类加载器的时候,扩展类加载器被设置为系统加载器的parent,因此当JVM想加载扩展类时,总是能够通过系统类加载器的parent属性获取到扩展类加载器,从而使用扩展类加载器去加载响应的类库。public class Launcher { private static URLStreamHandlerFactory factory =new Factoru(); private static Launcher launcher = new Launcher();//启动器 private static String bootClassPath = System.getProperty("sun.boot.class.path");//引导类加载器路径 private ClassLoader loader;//系统类加载器 public Launcher() { ClassLoader extc1; //创建扩展类加载器 extc1 = sun.misc.Launcher.ExtClassLoader.getExtClassLoader(); //创建系统类加载器 loader = sun.misc.Launcher.AppClassLoader.getAppClassLoader(extc1); } }
- @未完待续。。。。。。