ClassLoader 是 JVM 结构中很重要的一块,也可以说是整个 JVM 运行机制的入口,程序通过 ClassLoader 将编译好的字节码文件加载到内存中,生成 Class,进而创建对象,之后才能进行各种运算、解析,最终生成机器码提交到操作系统中。
JVM 结构如下图所示。
ClassLoader 有 4 种具体的分类:
1、BootstrapClassLoader
2、ExtClassLoader
3、AppClassLoader
4、自定义 ClassLoader
BootstrapClassLoader 用来加载 Java 的核心类库,即存放在 java.* 包中的字节码文件,如 java.util.List、java.io.InputStream、java.lang.Integer 等。
ExtClassLoader 用来加载 Java 的扩展类库,即存放在 javax.* 包中的字节码文件,如 javax.sql.DataSource、javax.net.SocketFactory 等。
AppClassLoader 用来加载当前程序所在目录的类,即开发者自己编写的 Java 文件对应的字节码文件。
自定义的 ClassLoader 指开发者根据具体需求编写的类加载器,可以实现定制化加载。
接下来我们来实现一个自定义的 ClassLoader,首先是准备工作,ClassLoader 的作用是将字节码文件加载到内存中,所有你得先有字节码文件。
1、创建一个 Java 文件。
代码语言:javascript复制public class HelloWorld{
public HelloWorld(){
System.out.println("创建了HelloWorld对象");
}
}
2、将其编译成字节码文件。
代码语言:javascript复制javac HelloWorld.java
有了字节码文件,接下来就可以编写自定义 ClassLoader,并通过其加载字节码文件了,ClassLoader 具体的工作流程主要是通过两个方法完成类加载的,分别是 findClass 和 defineClass。
findClass 根据路径加载字节码文件,然后交给 defineClass,再把字节码转化为 Class。自定义 ClassLoader 需要开发者对 findClass 方法进行重写,完成加载字节码文件的操作,之后再将字节数据传给 ClassLoader 的 defineClass 方法即可,根据这个思路,我们来实现代码。
3、创建自定义 ClassLoader,并继承 ClassLoader。
代码语言:javascript复制import java.io.*;
public class MyClassLoader extends ClassLoader {
private String path;
public MyClassLoader(String path) {
this.path = path;
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
String classPath = path name ".class";
InputStream inputStream = null;
ByteArrayOutputStream outputStream = null;
try {
inputStream = new FileInputStream(classPath);
outputStream = new ByteArrayOutputStream();
int temp = 0;
while((temp = inputStream.read()) != -1){
outputStream.write(temp);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
outputStream.close();
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
byte[] bytes = outputStream.toByteArray();
return defineClass(name,bytes,0,bytes.length);
}
}
在 findClass 方法中,我们通过 IO 流读取本地编译好的字节码文件,生成字节数组,再将字节数组传给 ClassLoader 的 defineClass 方法即可。
4、进行测试,实例化 MyClassLoader,并通过该实例化对象加载字节码文件获取 Class 对象。
代码语言:javascript复制public class Test {
public static void main(String[] args) {
MyClassLoader myClassLoader = new MyClassLoader("/Users/southwind/myjava/");
try {
Class clazz = myClassLoader.findClass("HelloWorld");
System.out.println(clazz);
System.out.println(clazz.getConstructor().newInstance());
} catch (Exception e) {
e.printStackTrace();
}
}
}
5、运行结果如下图所示。
HelloWorld 字节码文件加载成功,以上就是自定义 ClassLoader 的用法,你学会了吗?