类加载的机制的层次结构
每个编写的“.java”扩展名类文件都存储着需要执行的程序逻辑,这些“.java”文件经过Java编译器编译成扩展名为“class”的文件,“class"文件中保存着java代码经过转换后的虚拟机指令,当需要使用某个类时,虚拟机将会加载它的“.class”文件,并创建对应的class对象,将class文件加载到虚拟机的内存,这个过程成为类加载,这里我们需要了解一下类加载的过程。
- 加载:类加载过程的一个阶段:通过一个类的完全限定查找此类字节码文件,并利用字节码文件创建一个class对象。
- 验证:目的在于确保class文件的字节流中包含信息符合当前虚拟机的要求,不会危害虚拟机自身安全。主要包括四种验证,文件格式验证,元数据验证,字节码验证,符号引用验证,
- 准备:为类变量分配内存并且设置该类变量的初始值即0,这里不包含用final修饰的static,因为final在编译的时候就会分配,注意这里不会为实例变量分配初始化,类变量会分配在方法区中,而实例变量会随着对象一起分配到Java堆中。
- 解析:主要将常量池中的符号引用替换为直接引用的过程。符号引用就是一组符号来描述目标,可以是任何字面量,而直接引用就是直接指向目标的指针、相对偏移量或一个间接定位到目标i的句柄。
- 初始化:类加载最后阶段,若该类具有超类,则对其进行初始化,执行静态初始化器和静态初始化成员变量。
启动类加载器
启动类加载器主要加载的是JVM自身需要的类,这个类加载使用C++语言实现,是虚拟机自身一部分,它负责将核心库和jar包加载到内存中,
扩展类加载器
扩展类加载器是指Sun公司实现的 sun.misc.Launcher$ExtClassLoader 类,由Java语言实现的,是Launcher的静态内部类,负责加载<JAVA_HOME>/lib/ext目录下或者由系统变量-Djava.ext.dir指定为路径中的类库,开发者可以直接使用标准扩展类加载器。
系统类加载器
也称应用程序加载器,是指Sun公司实现的,负责加载系统类路径下的指定类库。在Java的日常开发中,类的加载几乎是由上述3中类加载器相互配合执行的,在必要的时候,还可以自定义类加载器,需要注意的是,Java虚拟机对class文件采用的是按需加载的方式,也就是说当需要使用该类时才会将它的class文件加载到内存生成的class对象。而且加载某个类的class文件时,Java虚拟机采用的是双亲委派模式即把请求交由父类处理,
理解双亲委派模式
双亲委派模式工作原理:双亲委派模式要求除了顶层的启动类加载器外,其余的类加载器都应当有自己的父类加载器,请注意双亲委派模式中的父子关系并非通常所有的类继承关系,而是采用组合关系来复用父类加载器的相关代码。
双亲委派模式的工作原理是,如果一个类加载器收到了类加载请求,它并不会自己先去加载,而是把这个请求委托给父类的加载器去执行,如果父类加载器还存在其父类加载器,则进一步向上委托,依次递归,请求最终将到达顶层的启动类加载器,如果父类加载器可以完成类加载任务,就成功返回,倘若父类加载器无法完成加载任务,子加载器才会尝试自己去加载,这就是双亲委派模式,即每个儿子都很懒,每次有活就丢给父亲去干,直到父亲说这件事我也干不了时,儿子自己想办法去完成。
双亲委派模式优势
采用双亲委派模式的好处是Java类随着它的类加载器一起具备了一种具有优先级的层次关系,通过这种层次关系可以避免类的重复加载,当父亲已经加载了该类时,就没有必要子ClassLoader再加载一次。