执行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写成;
在加载类时,每个类加载器会先将加载类的任务交给父加载器,如果父加载器找不到则由自己进行加载。所以加载指定类时,会以如下顺序进行:
如果所有的类加载器都找不到指定类,就会抛出java.lang.NoClassDefFoundError
类加载器都继承自抽象类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虚拟机》)