如何加载相同的类?怎么打破双亲委派模型?

2 个回答

  • 澜夜师兄
    勇敢一点吧!我们不会比今年更年轻了。
    ### 如何加载相同的类? 在Java中,类的加载由类加载器(ClassLoader)负责。通常,Java采用双亲委派模型来确保类的加载过程的一致性和安全性。双亲委派模型的基本原理是: 1. 一个类加载器在加载类时,先将请求委派给其父类加载器。 2. 父类加载器会递归地将请求委派给其父类加载器,直到顶层的Bootstrap ClassLoader。 3. 如果父类加载器无法找到该类,则子类加载器才会尝试加载该类。 ### 打破双亲委派模型 有时候,我们需要加载相同名称的类,但需要不同的实现。这时可以通过自定义类加载器并打破双亲委派模型来实现。要打破双亲委派机制,需要继承`ClassLoader`类,并重写`loadClass`和`findClass`方法。 以下是一个示例代码,展示如何实现自定义类加载器并打破双亲委派模型: ```java import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; public class CustomClassLoader extends ClassLoader { private String classPath; public CustomClassLoader(String classPath) { this.classPath = classPath; } @Override public Class<?> loadClass(String name) throws ClassNotFoundException { // 检查类是否已经被加载 Class<?> loadedClass = findLoadedClass(name); if (loadedClass != null) { return loadedClass; } // 委派给父类加载器(可选,如果希望完全打破双亲委派,可以注释掉) try { loadedClass = getParent().loadClass(name); if (loadedClass != null) { return loadedClass; } } catch (ClassNotFoundException e) { // 如果父类加载器无法加载类,则继续尝试 } // 自定义加载类 return findClass(name); } @Override protected Class<?> findClass(String name) throws ClassNotFoundException { byte[] classData = getClassData(name); if (classData == null) { throw new ClassNotFoundException(); } else { return defineClass(name, classData, 0, classData.length); } } private byte[] getClassData(String className) { String path = classPath + File.separatorChar + className.replace('.', File.separatorChar) + ".class"; try (FileInputStream inputStream = new FileInputStream(path); ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream()) { int bufferSize = 1024; byte[] buffer = new byte[bufferSize]; int bytesNumRead; while ((bytesNumRead = inputStream.read(buffer)) != -1) { byteArrayOutputStream.write(buffer, 0, bytesNumRead); } return byteArrayOutputStream.toByteArray(); } catch (IOException e) { e.printStackTrace(); return null; } } public static void main(String[] args) { CustomClassLoader customClassLoader = new CustomClassLoader("path/to/your/classes"); try { Class<?> clazz = customClassLoader.loadClass("YourClassName"); Object instance = clazz.newInstance(); System.out.println(instance.getClass().getClassLoader()); } catch (Exception e) { e.printStackTrace(); } } } ``` ### 解释 1. **CustomClassLoader构造函数**:接收类文件的路径,以便从该路径加载类文件。 2. **loadClass方法**: - 首先,检查类是否已经被加载。如果已经加载,则返回该类。 - 尝试委派给父类加载器加载类(这是可选的,如果需要完全打破双亲委派,可以注释掉这一部分)。 - 如果父类加载器无法加载类,则调用`findClass`方法进行自定义加载。 3. **findClass方法**: - 通过`getClassData`方法读取类文件的字节码,并调用`defineClass`方法将字节码转换为Class对象。 4. **getClassData方法**: - 根据类名构建类文件的路径,读取类文件的字节码并返回。 通过自定义类加载器并重写`loadClass`和`findClass`方法,可以实现加载相同名称的不同实现类,打破双亲委派模型。
    编辑于 2024-05-12 04:24 •IP属地 北京
    举报
    评论
    收藏

  • 梅拾璎
    希望有人告诉你开心比对错更重要。
    在Java中,类加载器(ClassLoader)负责加载Java类。默认情况下,Java使用双亲委派模型(Parent Delegation Model)来加载类,即子类加载器会先委托父类加载器尝试加载类。如果父类加载器无法加载该类,才会由子类加载器尝试加载。 要实现自定义类加载器并控制类的加载行为,你可以选择: 1. 不打破双亲委派模型 2. 打破双亲委派模型 ### 1. 不打破双亲委派模型 如果你不想打破双亲委派模型,只需重写`findClass`方法。这种方式下,类加载器仍会先尝试使用父加载器加载类。 ```java public class CustomClassLoader extends ClassLoader { @Override protected Class<?> findClass(String name) throws ClassNotFoundException { byte[] classData = getClassData(name); if (classData == null) { throw new ClassNotFoundException(); } else { return defineClass(name, classData, 0, classData.length); } } private byte[] getClassData(String name) { // 读取类文件的字节码 // 例如:从文件系统、网络或其他来源获取字节码 return null; } } ``` ### 2. 打破双亲委派模型 如果你想打破双亲委派模型,需要重写`loadClass`方法。这种方式下,类加载器不会先委托父加载器,而是直接尝试自己加载类。 ```java public class CustomClassLoader extends ClassLoader { @Override public Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException { // 检查类是否已经加载 Class<?> c = findLoadedClass(name); if (c == null) { try { // 尝试加载系统类 c = getSystemClassLoader().loadClass(name); } catch (ClassNotFoundException e) { // 系统类加载器也无法加载时,尝试自定义加载 c = findClass(name); } } if (resolve) { resolveClass(c); } return c; } @Override protected Class<?> findClass(String name) throws ClassNotFoundException { byte[] classData = getClassData(name); if (classData == null) { throw new ClassNotFoundException(); } else { return defineClass(name, classData, 0, classData.length); } } private byte[] getClassData(String name) { // 读取类文件的字节码 // 例如:从文件系统、网络或其他来源获取字节码 return null; } } ``` ### 结论 1. **不打破双亲委派模型**:重写`findClass`方法。 2. **打破双亲委派模型**:重写`loadClass`方法。 根据你的需求选择适合的方法来实现自定义类加载器。
    编辑于 2022-08-02 23:16 •IP属地 北京
    举报
    评论
    收藏