- 隐式装载, 程序在运行过程中当碰到通过new 等方式生成对象时,隐式调用类装载器加载对应的类到jvm中。
- 显式装载, 通过class.forname()等方法,显式加载需要的类。
Bootstrp loader Bootstrp加载器是用C++语言写的,它是在Java虚拟机启动后初始化的,它主要负责加载%JAVA_HOME%/jre/lib,-Xbootclasspath参数指定的路径以及%JAVA_HOME%/jre/classes中的类。
ExtClassLoader Bootstrp loader加载ExtClassLoader,并且将ExtClassLoader的父加载器设置为Bootstrp loader.ExtClassLoader是用Java写的,具体来说就是 sun.misc.Launcher$ExtClassLoader,ExtClassLoader主要加载%JAVA_HOME%/jre/lib/ext,此路径下的所有classes目录以及java.ext.dirs系统变量指定的路径中类库。
AppClassLoader Bootstrp loader加载完ExtClassLoader后,就会加载AppClassLoader,并且将AppClassLoader的父加载器指定为 ExtClassLoader。AppClassLoader也是用Java写成的,它的实现类是 sun.misc.Launcher$AppClassLoader,另外我们知道ClassLoader中有个getSystemClassLoader方法,此方法返回的正是AppclassLoader.AppClassLoader主要负责加载classpath所指定的位置的类或者是jar文档,它也是Java程序默认的类加载器。
类加载器继承关系
java的类加载器采用了委托模型机制,这个机制简单来讲,就是类装载器有载入类的需求时,会先请示其Parent使用其搜索路径帮忙载入,如果Parent 找不到,那么才由自己依照自己的搜索路径搜索类。
加载class文件的步骤如下:
1、装载:查找和导入Class文件
2、链接:其中解析步骤是可以选择的 (a)检查:检查载入的class文件数据的正确性 (b)准备:给类的静态变量分配存储空间 (c)解析:将符号引用转成直接引用
3、初始化:对静态变量,静态代码块执行初始化工作
定义自已的类加载器分为两步:
- 继承java.lang.ClassLoader
- 重写父类的findClass方法
线程上下文类加载器(context class loader)是从 JDK 1.2 开始引入的。类 java.lang.Thread中的方法 getContextClassLoader()和 setContextClassLoader(ClassLoader cl)用来获取和设置线程的上下文类加载器。如果没有通过 setContextClassLoader(ClassLoader cl)方法进行设置的话,线程将继承其父线程的上下文类加载器。Java 应用运行的初始线程的上下文类加载器是系统类加载器。在线程中运行的代码可以通过此类加载器来加载类和资源。
CustomClassLoader.java
public class CustomClassLoader extends ClassLoader {
public CustomClassLoader(ClassLoader parent) {
super(parent);
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
byte[] date = getClassDate(name);
if (date != null) {
return defineClass(name, date, 0, date.length);
}
throw new ClassNotFoundException();
}
private byte[] getClassDate(String className) {
String filename = className.replaceAll("\\.", File.separator).concat(".class");
try (InputStream in = new FileInputStream(filename);
ByteArrayOutputStream bos = new ByteArrayOutputStream()) {
byte[] buffer = new byte[1024];
int len = 0;
while ((len = in.read(buffer)) != -1) {
bos.write(buffer, 0, len);
}
return bos.toByteArray();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}
Main.java
public class Main {
public static void main(String[] args) {
// 获取当前的类加载器
ClassLoader currentClassLoader = Main.class.getClassLoader();
// 新建类加载器
ClassLoader customClassLoader = new CustomClassLoader(currentClassLoader);
// 设置当前线程使用自定义的类加载器
Thread.currentThread().setContextClassLoader(customClassLoader);
// 查看子线程的类加载器
new Thread(new Runner()).start();
}
}
class Runner implements Runnable {
@Override
public void run() {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
System.out.println(classLoader);
}
}
输出
com.classload.CustomClassLoader@60cb300b