Java类加载器(ClassLoader)是Java虚拟机(JVM)用于在运行时动态加载Java类的部件。类加载器通过将字节码文件加载到JVM中将Java类从磁盘或网络中加载到内存中。Java类加载器通常以层次结构的方式组织。在类加载器层次结构中,根加载器是虚拟机的一部分,负责从JVM默认搜索路径加载Java类库,而其他加载器则依次负责从指定位置加载 Java 类。
Java类加载器的使用攻略包括以下步骤:
- 创建类加载器对象:Java类加载器是由抽象类java.lang.ClassLoader派生的类。您可以使用这个抽象类的子类来创建一个类加载器对象。例如,可以使用java.lang.ClassLoader.getSystemClassLoader()方法来获取默认的系统类加载器。
ClassLoader classLoader = ClassLoader.getSystemClassLoader();
- 加载类:使用loadClass方法来动态加载Java类。loadClass会在类加载器的层次结构中查找Java类并加载它。如果类加载器无法找到类,则会引发ClassNotFoundException异常。
Class<?> myClass = classLoader.loadClass("com.mycompany.myproject.MyClass");
- 使用newInstance方法创建类实例:在通过类加载器加载Java类后,我们可以使用反射 API 中的newInstance方法创建该类的实例。
Object myObj = myClass.newInstance();
- 示例1 – 加载自定义类:以下示例演示如何创建一个自定义的Java类,并将其加载到Java虚拟机中。
// 定义自定义类
public class MyCustomClass {
public void sayHello() {
System.out.println("Hello World!");
}
}
// 自定义类加载器
public class MyClassLoader extends ClassLoader {
@Override
public Class<?> findClass(String name) throws ClassNotFoundException {
if ("MyCustomClass".equals(name)) {
byte[] b = new byte[1024];
InputStream inputStream = this.getClass().getResourceAsStream("/MyCustomClass.class");
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
int len = 0;
try {
while ((len = inputStream.read(b)) != -1) {
byteArrayOutputStream.write(b, 0, len);
}
} catch (IOException e) {
e.printStackTrace();
}
return defineClass(name, byteArrayOutputStream.toByteArray(), 0, byteArrayOutputStream.size());
}
return super.findClass(name);
}
}
// 主函数
public static void main(String[] args) {
// 使用自定义类加载器加载自定义类
MyClassLoader myClassLoader = new MyClassLoader();
Class<?> myClass = null;
try {
myClass = myClassLoader.loadClass("MyCustomClass");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
// 创建自定义类实例
Object myObj = null;
try {
myObj = myClass.newInstance();
} catch (InstantiationException | IllegalAccessException e) {
e.printStackTrace();
}
// 调用自定义类方法
Method sayHelloMethod = null;
try {
sayHelloMethod = myClass.getDeclaredMethod("sayHello");
} catch (NoSuchMethodException | SecurityException e) {
e.printStackTrace();
}
try {
sayHelloMethod.invoke(myObj);
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
e.printStackTrace();
}
}
在上述示例中,我们定义了一个MyCustomClass类,它包含一个sayHello方法。我们还定义了一个MyClassLoader类,它是一个自定义的类加载器,它可以从指定位置加载MyCustomClass类并将其转换为字节流。我们使用MyClassLoader来加载MyCustomClass,并使用反射 API 中的newInstance方法创建该类的实例。最后,我们使用反射 API 中的getDeclaredMethod来获取MyCustomClass类的sayHello方法,然后使用invoke方法来调用此方法。
- 示例2 – 加载资源文件:以下示例演示如何使用类加载器加载资源文件。
// 加载资源文件
ClassLoader classLoader = ClassLoader.getSystemClassLoader();
InputStream inputStream = classLoader.getResourceAsStream("demo.txt");
Scanner scanner = new Scanner(inputStream);
while (scanner.hasNextLine()) {
System.out.println(scanner.nextLine());
}
scanner.close();
在上述示例中,我们使用了ClassLoader.getSystemClassLoader()来获取默认的系统类加载器。然后我们使用getResourceAsStream方法来加载demo.txt文件。注意,在getResourceAsStream中,demo.txt表示资源文件的相对路径。最后,我们使用Scanner来读取文件内容并输出。