JAVA加载类说明
当执行某个类的时候, java.exe 会帮助我们找到 JRE ,接着找到位于 JRE 内部的 jvm.dll ,这才是真正的 Java 虚拟机器 , 最后加载动态库,激活 Java 虚拟机器。虚拟机器激活以后,会先做一些初始化的动作,比如说读取系统参数等。一旦初始化动作完成之后,就会产生第一个类加载器―― Bootstrap Loader , Bootstrap Loader 是由 C++ 所撰写而成,这个 Bootstrap Loader 所做的初始工作中,除了一些基本的初始化动作之外,最重要的就是加载 Launcher.java 之中的 ExtClassLoader ,并设定其 Parent 为 null ,代表其父加载器为 BootstrapLoader 。然后 Bootstrap Loader 再要求加载 Launcher.java 之中的 AppClassLoader ,并设定其 Parent 为之前产生的 ExtClassLoader 实体。这两个加载器都是以静态类的形式存在的。这里要请大家注意的是, Launcher$ExtClassLoader.class 与 Launcher$AppClassLoader.class 都是由 Bootstrap Loader 所加载,所以 Parent 和由哪个类加载器加载没有关系。
加载器对应的系统参数如下:
BootstrapLoader : sun.boot.class.path
ExtClassLoader: java.ext.dirs
AppClassLoader: java.class.path
执行java XXX.class的过程
找到JRE——》找到jvm.dll——》启动JVM并进行初始化——》产生Bootstrap Loader——》载入ExtClassLoader——》载入AppClassLoader——》执行java XXX.class
加载类工作原理
加载类采用的是全盘负责委托机制(双亲委托)。所谓全盘负责,即是当一个classloader加载一个Class的时候,这个Class所依赖的和引用的所有 Class也由这个classloader负责载入,除非是显式的使用另外一个classloader载入;委托机制则是先让parent(父)类加载器 (而不是super,它与parent classloader类不是继承关系)寻找,只有在parent找不到的时候才从自己的类路径中去寻找。此外类加载还采用了cache机制,也就是如果 cache中保存了这个Class就直接返回它,如果没有才从文件中读取和转换成Class,并存入cache,这就是为什么我们修改了Class但是必须重新启动JVM才能生效的原因。
加载类*.class过程
AppClassLoader 要载入*.class时,首先请求其Parent ClassLoader,也就是ExtClassLoader 来载入,而ExtClassLoader 又请求其Parent ClassLoader,即Bootstrap Loader 来载入Class。如果找到*.class,则加载,如果Bootstrap Loader 无法在其搜寻路径下找到,则由ExtClassLoader 在其搜寻路径下查找该类,如果找到就加载,找不到的话,最后只好由AppClassLoader 在自己搜寻路径底下查找,如果找到*.class,则加载,否则报异常。
测试类加载路径和父加载器的示例代码
import java.net.URL;
import java.net.URLClassLoader;
public class ClassTest {
public static void main(String[] args) {
System.out.println("-------------------------------------");
System.out.println(System.getProperty("sun.boot.class.path"));
URL[] urls=sun.misc.Launcher.getBootstrapClassPath().getURLs();
for (int i = 0; i < urls.length; i++) {
System.out.println(urls[i].toExternalForm());
}
System.out.println("-------------------------------------");
System.out.println(System.getProperty("java.ext.dirs"));
ClassLoader extensionClassloader=ClassLoader.getSystemClassLoader().getParent();
System.out.println("the parent of extension classloader : "+extensionClassloader.getParent());
System.out.println("extension classloader can use thess jars:");
URL[] extURLs = ((URLClassLoader)ClassLoader.getSystemClassLoader().getParent()).getURLs();
for (int i = 0; i < extURLs.length; i++) {
System.out.println(extURLs[i]);
}
System.out.println("-------------------------------------");
System.out.println(System.getProperty("java.class.path"));
ClassLoader systemClassloader=ClassLoader.getSystemClassLoader();
URL[] dd = ((URLClassLoader)ClassLoader.getSystemClassLoader()).getURLs();
for (int i = 0; i < dd.length; i++) {
System.out.println("********* "+dd[i]);
}
System.out.println("the parent of system classloader : "+systemClassloader.getParent());
}
}