6、类加载器深入解析与重要特性剖析
6.1、类加载器介绍
类加载器用来把类的.class文件加载到java虚拟机中。从JDK1.2版本开始,类的加载过程采用“双亲委托机制”,这种机制能更好的保证java平台的安全。在“双亲委托机制”中,各个加载器按照父子关系(实际是一种包含关系)形成了树形结构,除了java虚拟机自带的根类加载器外,其余的类加载器都有且只有一个父加载器。双亲委托机制将在下章介绍。
6.2、类加载器分类
有两种类型的类加载器:
- java虚拟机自带的类加载器
- 根类加载器(Bootstrap)
- 该加载器没有父加载器,它负责加载虚拟机的核心类库,如java.lang.*等。根类加载器从系统属性sun.boot.class.path所指定的目录中加载类库。根类加载器的实现依赖底层操作系统,属于虚拟机实现的一部分,没有继承java.lang.ClassLoader类。
- 扩展类加载器(Extension)
- 它的父加载器为根类加载器。它从java.ext.dirs系统属性所指定的目录中加载类库,或者从JDK的安装目录的jre\lib\ext子目录(扩展目录)下加载类库,如果把用户创建的jar文件放在这个目录下,也会自动由扩展类加载器加载。扩展类加载器是纯java类,是java.lang.ClassLoader类的子类。
- 系统(应用)类加载器(System)
- 也称为应用类加载器,它的父加载器为扩展类加载器。它从环境变量classpath或者系统属性java.class.path所指定的目录中加载类,它是用户自定义的类加载器的默认父加载器。系统类加载器是纯java类,是java.lang.ClassLoader类的子类。
- 用户自定义的类加载器
- java.lang.ClassLoader的子类
- 用户可以定制类的加载方式,java提供了抽象类java.lang.ClassLoader,所有用户自定义的类加载器都应该继承该类

6.3、定义类加载器和初始化类加载器
定义类加载器:
如果一个类加载器能够成功加载Test类,那么这个类加载器被称为定义类加载器。
初始化类加载器:
所有能成功返回Class对象引用的类加载器(包括定义类加载器)都被称为初始化类加载器。
6.4、获得ClassLoader的几种途径

package com.shtec.classLoader; /** * 获得ClassLoader的几种途径: * @author sunhao * */ public class Test02 { public static void main(String[] args) { //1、获得当前类的ClassLoader System.out.println("1、获得当前类的ClassLoader: " + Test02.class.getClassLoader()); //2、获得当前线程上下文的ClassLoader System.out.println("2、获得当前线程上下文的ClassLoader: " + Thread.currentThread().getContextClassLoader()); //3、获得系统或者应用的ClassLoader System.out.println("3、获得系统或者应用的ClassLoader: " + ClassLoader.getSystemClassLoader()); //输出: /* * 1、获得当前类的ClassLoader: sun.misc.Launcher$AppClassLoader@73d16e93 * 2、获得当前线程上下文的ClassLoader: sun.misc.Launcher$AppClassLoader@73d16e93 * 3、获得系统或者应用的ClassLoader: sun.misc.Launcher$AppClassLoader@73d16e93 */ } }
6.5、类的加载
类的加载指的是将类的class文件中的二进制数据读入到内存中,并将其放置在运行时数据区的方法区内,然后在内存中创建一个java.lang.Class对象。Class对象封装了类在方法区内的数据结构,并且向java程序员提供了访问方法区内的数据结构的接口。
6.6、类的加载时机
类加载器并不需要等到某个类被程序“首次主动使用”时再加载它。
JVM规范允许类加载器在预料某个类将要被使用时就预先加载它,如果在预先加载的过程中遇到了.class文件缺失或存在错误,类加载器必须在“程序首次主动使用”时才报告错误(LinkageError错误),如果这个类一直没有被程序主动使用,那么类加载器就不会报告错误。
点击查看【java程序对类主动使用的7种情况】
使用一个案例用来说明类的加载和类的初始化区别:
package com.shtec.classLoader; /** * 使用ClassLoader类的loadClass方法加载一个类,并不是对类的主动使用,因此不会导致类的初始化 * @author sunhao * */ public class Test01 { public static void main(String[] args) throws ClassNotFoundException { ClassLoader loader = ClassLoader.getSystemClassLoader(); Class<?> clazz = loader.loadClass("com.shtec.classLoader.Demo"); System.out.println(clazz); //输出: //class com.shtec.classLoader.Demo //反射属于程序对类的“主动使用”,因此会初始化类 clazz = Class.forName("com.shtec.classLoader.Demo"); System.out.println(clazz); //输出: //Demo static block //class com.shtec.classLoader.Demo } } class Demo{ static{ System.out.println("Demo static block"); } }

浙公网安备 33010602011771号