Java自定义类加载器

时间:2010-07-30 22:30:55

标签: java classloader

为什么我收到此错误的任何想法? (是的,我查了一下错误,但仍未找到解决方案)

我的错误:

Exception in thread "main" java.lang.ClassFormatError: Truncated class file
 at java.lang.ClassLoader.defineClass1(Native Method)
 at java.lang.ClassLoader.defineClass(Unknown Source)
 at java.lang.ClassLoader.defineClass(Unknown Source)
 at org.fellixombc.mysql.util.MysqlClassLoader.findClass(MysqlClassLoader.java:22)
 at org.fellixombc.mysql.util.MysqlClassLoader.loadClass(MysqlClassLoader.java:14)
 at org.fellixombc.mysql.Main.main(Main.java:9)

文件:

Main.java

package org.fellixombc.mysql;

import org.fellixombc.mysql.util.MysqlClassLoader;

public class Main {
    public static void main(String[] args) {
        MysqlClassLoader mcl = new MysqlClassLoader();
        try {
            mcl.loadClass("org.fellixombc.mysql.net.Client");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

Client.java:

package org.fellixombc.mysql.net;

public class Client {
    public Client() {
        System.out.println("Hello!");
    }
}

MysqlClassLoder.java:

package org.fellixombc.mysql.util;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;

public class MysqlClassLoader extends ClassLoader {
    public MysqlClassLoader() {
        super(MysqlClassLoader.class.getClassLoader());
    }

    @Override
    public Class<?> loadClass(String className) throws ClassNotFoundException {
        return findClass(className);
    }

    @Override
    public Class<?> findClass(String className) throws ClassNotFoundException {
        byte[] b = null;
        try {
            b = loadClassData(className);
            Class c = defineClass(className, b, 0, b.length);
            if(c != null)
                return c;
            return super.findClass(className);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    private byte[] loadClassData(String className) throws IOException {
        int size = className.length();
        byte buff[] = new byte[size];

        // Open the file
        FileInputStream fis = new FileInputStream("bin/" + className.replace('.', File.separatorChar) + ".class");
        fis.available();
        fis.read(buff);
        fis.close();

        return buff;
    }
}

2 个答案:

答案 0 :(得分:3)

是的,您最多读取的字节数等于文件名中的字符数。相反,您需要阅读整个文件。这是一种方法,使用你建议的readFully。

File f = new File("bin/" + className.replace('.', File.separatorChar) + ".class");
DataInputStream is = new DataInputStream(new FileInputStream(f));
int len = (int)f.length();
byte[] buff = new byte[len];
is.readFully(buff);
is.close();
return buff;

由于您没有处理像Object这样的内置类,我认为您需要从findClass中的loadClassData捕获FileNotFoundException,然后调用super.findClass。 E.g:

try {
  try {
    b = loadClassData(className);
  }
  catch(FileNotFoundException fnf) {
    return super.findClass(className);
  }
  Class c = defineClass(className, b, 0, b.length);
  if(c != null)
    return c;
  return super.findClass(className);
} catch (IOException e) {
  e.printStackTrace();
}
return null;

答案 1 :(得分:1)

在返回之前,您只从.class文件中读取 N 字节(N =类名长度)到缓冲区(在loadClassData中)。

在返回缓冲区以便正确定义类之前,需要读取整个类的内容。