Java 类加载机制中加载阶段怎么获取二进制字节流
在 java 类加载机制的加载(loading)阶段,虚拟机需要找到并读取类的二进制字节流。具体做法是依赖 classloader 的 findclass() 方法或 loadclass() 方法的实现逻辑,从文件系统、网络、数据库或动态生成等来源获取数据,并将其转换为字节数组。默认情况下,bootstrap 类加载器从 rt.jar 等核心库中查找,而用户自定义类加载器通常从本地文件系统的 .class 文件中读取。

如何自定义 ClassLoader 从特定路径加载类
要自定义类加载行为,需要继承 java.lang.ClassLoader 并重写 findClass(String name) 方法。在该方法中,通过指定的路径读取字节流,然后调用父类的 defineClass() 将字节数组转换为 java.lang.Class 对象。这样做可以绕过默认的搜索路径,实现从加密文件或远程服务器加载类的功能。

import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.InputStream;
public class CustomClassLoader extends ClassLoader {
private String classPath;
public CustomClassLoader(String classPath) {
this.classPath = classPath;
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
try {
// 构造文件路径
String filePath = classPath + name.replace('.', '/') + ".class";
InputStream is = new FileInputStream(filePath);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int bufferSize = 4096;
byte[] buffer = new byte[bufferSize];
int bytesNumRead;
// 读取字节流
while ((bytesNumRead = is.read(buffer)) != -1) {
baos.write(buffer, 0, bytesNumRead);
}
is.close();
baos.close();
// 定义类
byte[] byteArray = baos.toByteArray();
return defineClass(name, byteArray, 0, byteArray.length);
} catch (Exception e) {
throw new ClassNotFoundException(name, e);
}
}
public static void main(String[] args) throws Exception {
// 假设 D:classes 下有一个 com.example.MyClass.class
CustomClassLoader loader = new CustomClassLoader("D:\\classes\\");
Class<?> clazz = loader.loadClass("com.example.MyClass");
System.out.println("Loaded by: " + clazz.getClassLoader().getClass().getName());
}
}双亲委派模型在获取字节流时的作用是什么
双亲委派模型确保了类加载的安全性和一致性。当调用 loadClass() 时,它会先委托给父加载器处理。只有当父加载器无法找到该类时,当前加载器的 findClass() 才会被调用以获取字节流。这种机制防止了核心 API 被篡改,例如用户无法加载一个名为 java.lang.String 的恶意类,因为 Bootstrap 类加载器已经成功加载了核心的 String 类。
立即学习“Java免费学习笔记(深入)”;

import java.util.Arrays;
// 模拟双亲委派的简化逻辑
public class ParentDelegationDemo {
public static void main(String[] args) {
// 1. 尝试加载 java.lang.String
try {
Class<?> stringClass = Class.forName("java.lang.String", true, ParentDelegationDemo.class.getClassLoader());
System.out.println("Loaded String by: " + stringClass.getClassLoader());
// 输出: Loaded String by: null (Bootstrap Loader)
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
// 2. 尝试加载自定义类
try {
// 假设存在 com.demo.TestClass
Class<?> testClass = Class.forName("com.demo.TestClass", true, ParentDelegationDemo.class.getClassLoader());
System.out.println("Loaded TestClass by: " + testClass.getClassLoader());
} catch (ClassNotFoundException e) {
// 如果找不到,会抛出异常,但在实际 ClassLoader 中会触发 findClass
System.out.println("TestClass not found in parent, will trigger findClass");
}
}
}


















