## **类加载过程**
![](https://img.kancloud.cn/8b/ee/8bee3c18c3d1e0b3d4ed9cc3e8dd254e_735x583.jpg)
## **类加载时机**
Java虚拟机对class文件采用的是按需加载的方式,当需要使用该类时才会将它的class文件加载到内存生成class对象。只要存在于以下几个时机:
* 创建类的实例
* 访问某个类或接口的静态变量,或者对该静态变量赋值
* 调用类的静态方法
* 反射机制获取类
* 初始化一个类的子类(会首先初始化子类的父类)
* JVM启动时标明的启动类,即文件名和类名相同的那个类
## **类加载器**
JVM预定义有三种类加载器,当一个 JVM启动的时候,Java开始使用如下三种类加载器相互配合执行:
* **启动(Bootstrap)类加载器**
主要加载的是JVM自身需要的类(jre/lib路径下的核心类库)
* **扩展(Extension)类加载器**
负责加载jre/lib/ext目录下或者由系统变量\-Djava.ext.dir指定位路径中的类库
* **系统(System)类加载器**
负责加载系统类路径java -classpath或\-D java.class.path 指定路径下的类库,也就是我们经常用到的classpath路径,开发者可以直接使用系统类加载器
## **类加载机制**
Java虚拟机采用的是双亲委派模式来处理类的加载。所谓的双亲委派,则是先让父类加载器试图加载该Class,只有在父类加载器无法加载该类时才尝试从自己的类路径中加载该类。通俗的讲,就是某个特定的类加载器在接到加载类的请求时,首先将加载任务委托给父加载器,父类如果还存在父类,则交给他的父类,依次递归,如果父加载器可以完成类加载任务,就成功返回;只有父加载器无法完成此加载任务时,才自己去加载。采用这种向上递归的方式可以保障每个类都只被加载一次。
**各个加载器的父类关系**:
* 启动类加载器(BootstrapLoader),由C++实现,没有父类。
* 拓展类加载器(ExtClassLoader),由Java语言实现,父类加载器为BootstrapLoader
* 系统类加载器(AppClassLoader),由Java语言实现,父类加载器为ExtClassLoader
* 自定义类加载器,父类加载器肯定为AppClassLoader。
## **自定义类加载器**
```
public class MyClassloader extends ClassLoader {
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
try {
String fileName = name.substring(name.lastIndexOf(".") + 1) + ".class";
// 读取字节
InputStream is = this.getClass().getResourceAsStream(fileName);
byte[] bytes = new byte[is.available()];
is.read(bytes);
// 将byte字节流解析成jvm能够识别的Class对象
return defineClass(name, bytes, 0, bytes.length);
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}
```