写了一个自定义的ClassLoader,一般情况下正常,但是如果加载的类的父类是另外一个ClassLoader加载的,则会抛出java.lang.ClassFormatError,请问有人碰到过这样的情况吗?这是什么原因呢?

解决方案 »

  1.   

    估计是你的defineClass的问题 看看你的代码
      

  2.   

    因为 加载一个类的时候,首先会加载它的父类。所以如果你的classloader没有加载过这个类的父类,就会出问题。这时候你需要让classloader将这些父类都先加载一遍。也就是这些类在你的环境中有两个版本。
      

  3.   

    java.lang.ClassFormatError
    类文件错误,也就是说你没有把这个类加载上去。
      

  4.   

    是这样的,在类加载前要加载该类的父类不错,楼主加载的这个类的父类是由另外一个类加载器加载的,所以本类的加载器无法加载其父类。那么如何让其正常加载呢?有两个办法。其一,让该类的加载器同时能够加载其父类,就是让它能够找到其父类的所在位置并加载它,但是这样就让这个父类被两个加载器各加载了一次;其二,让该类的加载器能够访问该类的父类的加载器,使得它能够直接由其父类加载器得到其父类的class,具体做法也不难,参见JavaAPI就有说明,只在加载的方法里面,在其加载一个类之前先去其父类加载器寻找该类,如果有,就直接使用即可。
      

  5.   

    这是一个例子:类A和B,A是B的父类。然后有两个类加载器,ParentLoader和ChildLoader,类A由ParentLoader加载,而类B由ChildLoader加载。代码如下:
    -------------------------------------------------------------------
    ParentLoader:
    package test_classloader;import java.io.File;
    import java.io.FileInputStream;
    import java.io.IOException;public class ParentLoader extends ClassLoader{
    private final static String FILE = "d:/test/A.class";

    public Class findClass(String name) throws ClassNotFoundException{
    if(!"test_class.A".equals(name)) 
    throw new ClassNotFoundException("No class " + name + " found.");

            byte[] b = loadData();

            Class cls = super.defineClass(name, b, 0, b.length);
            return cls;
        }

    private byte[] loadData(){
    System.out.println("Loaded A.");

    File file = new File(FILE);
    byte[] data = new byte[(int)file.length()];
    FileInputStream fis = null;
    try {
    fis = new FileInputStream(file);
    fis.read(data);
    } catch (IOException e) {
    e.printStackTrace();
    } finally {
    if(fis != null) {
    try {
    fis.close();
    } catch (IOException e) {
    e.printStackTrace();
    }
    }
    }

    return data;
    }}
    -------------------------------------------------------------------
    ChildLoader:
    package test_classloader;import java.io.File;
    import java.io.FileInputStream;
    import java.io.IOException;public class ChildLoader extends ClassLoader {
    private final static String FILE = "d:/test/B.class";

    public ChildLoader(ClassLoader parent){
    super(parent);
    }

    public Class findClass(String name) {
    byte[] b = loadData();
            return super.defineClass(name, b, 0, b.length);
    }

    private byte[] loadData(){
    System.out.println("Loaded B."); File file = new File(FILE);
    byte[] data = new byte[(int) file.length()];
    FileInputStream fis = null;
    try {
    fis = new FileInputStream(file);
    fis.read(data);
    } catch (IOException e) {
    e.printStackTrace();
    } finally {
    if (fis != null) {
    try {
    fis.close();
    } catch (IOException e) {
    e.printStackTrace();
    }
    }
    } return data;
    }
    }
    -------------------------------------------------------------------
    这样就可以了,类加载器是先由其父类加载器去尝试加载,如果没有,则再由子加载器加载的,
    希望这些能对楼主有用,^_^
      

  6.   

    上面可以正确执行,但是如果A.class调用其它*.class,则此时ClassLoader为系统AppClassLoader。如果要求A调用的class也是ChildLoader?谢先了!