回答
自定义类加载器可以让我们在应用程序中实现特定的类加载逻辑,例如从特定路径加载类、动态加载类、实现热部署等。要自定义一个类加载器只需要两步即可:
- 继承 ClassLoader
- 重写
findClass()
。在这个方法内我们可以自定义如何查找和加载类的字节码。
需要注意的是,如果不想打破双亲委派模型,我们就只需要重写 findClass()
。但如果想破坏双亲委派模型,则我们需要重写整个 loadClass()
。但是,在实际应用过程中,如果没有特殊需求,Java 官方推荐重写 findClass()
,而不是重写整个 loadClass()
。这样我们即可以按照自己的想法来加载类,也能保证自定义的类加载器符合双亲委派机制。
下面是一个自定义类加载器的简单例子:
- 自定义类加载器
public class CustomClassLoader extends ClassLoader {
private String classPath;
public CustomClassLoader(String classPath) {
this.classPath = classPath; // 指定类文件的存放目录
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
// 将类名转换为文件路径
String filePath = classPath + File.separator + name.replace('.', File.separatorChar) + ".class";
File classFile = new File(filePath);
if (!classFile.exists()) {
throw new ClassNotFoundException("Class not found: " + name);
}
try {
// 读取字节码
byte[] classData = Files.readAllBytes(classFile.toPath());
return defineClass(name, classData, 0, classData.length); // 定义类
} catch (IOException e) {
throw new ClassNotFoundException("Could not load class: " + name, e);
}
}
}
- 使用自定义类加载器
public class CustomClassLoaderTest {
public static void main(String[] args) {
// 设置类文件的存放路径
String classPath = "D:\\workspace"; // 修改为你的类文件存放目录
CustomClassLoader customClassLoader = new CustomClassLoader(classPath);
try {
// 加载指定的类
Class<?> myClass = customClassLoader.loadClass("com.skjava.TestClass");
Object obj = myClass.getDeclaredConstructor().newInstance(); // 创建实例
// 调用方法
myClass.getMethod("display").invoke(obj);
} catch (Exception e) {
e.printStackTrace();
}
}
}