【发布时间】:2009-11-23 04:28:54
【问题描述】:
如果已经将整个 .class 文件序列化为 byte[],并且假设类的名称是已知的(与 byte[] 一起传递),那么如何转换 byte[] -> Class -> 然后加载它到 JVM 以便我以后可以通过调用 Class.forName() 来使用它?
注意: 我这样做是因为我将 .class 发送到另一个主机,而主机的 JVM 不知道这个 .class。
【问题讨论】:
标签: java classloader
如果已经将整个 .class 文件序列化为 byte[],并且假设类的名称是已知的(与 byte[] 一起传递),那么如何转换 byte[] -> Class -> 然后加载它到 JVM 以便我以后可以通过调用 Class.forName() 来使用它?
注意: 我这样做是因为我将 .class 发送到另一个主机,而主机的 JVM 不知道这个 .class。
【问题讨论】:
标签: java classloader
我现在实际上在测试中使用这样的东西来将一组类定义作为 byte[] 提供给 ClassLoader:
public static class ByteClassLoader extends URLClassLoader {
private final Map<String, byte[]> extraClassDefs;
public ByteClassLoader(URL[] urls, ClassLoader parent, Map<String, byte[]> extraClassDefs) {
super(urls, parent);
this.extraClassDefs = new HashMap<String, byte[]>(extraClassDefs);
}
@Override
protected Class<?> findClass(final String name) throws ClassNotFoundException {
byte[] classBytes = this.extraClassDefs.remove(name);
if (classBytes != null) {
return defineClass(name, classBytes, 0, classBytes.length);
}
return super.findClass(name);
}
}
【讨论】:
使用ClassLoader中的defineClass(String, byte[], int, int) 方法
【讨论】:
扩展ClassLoader,然后在方法defineClass() 中执行必要的调用以获取您的byte[]。相反,您可以在findClass() 中执行此操作。因此,您将在开始时加载此 ClassLoader,或者在您需要通过数组定义类时使用它。
public class ByteArrayClassLoader extends ClassLoader {
public Class findClass(String name) {
byte[] ba = /* go obtain your byte array by the name */;
return defineClass(name,ba,0,ba.length);
}
}
【讨论】:
好的,这就是我所做的:
public class AgentClassLoader extends ClassLoader
{
public void loadThisClass(ClassByte classByte_)
{
resolveClass(defineClass(classByte_.getName(),
classByte_.getBytes(),
0,
classByte_.getBytes().length));
}
}
我希望将类加载到 JVM 中?如果这真的有效,为什么 Java 实现者不同时创建 defineClass 和 resolveClass 公共方法?我真的很想知道他们在想什么。哪位大神可以赐教一下?
为了完整起见,这里是 ClassByte
import java.io.Serializable;
public class ClassByte implements Serializable
{
private String name;
private byte[] bytes;
ClassByte(String name_, byte[] bytes_)
{
name = name_;
bytes = bytes_;
}
public String getName()
{
return name;
}
public byte[] getBytes()
{
return bytes;
}
}
【讨论】:
defineClass。这有可能危及安全性,并且通常会使非常奇怪的事情发生。最好只在自定义类加载器上允许这样做。
Alex 的回答是正确的,但是如果你的类之间有继承关系,你需要确保先加载父类。否则类加载器将无法定义它。
【讨论】:
getName时会加载String。但是,超类/接口需要在加载类的同时或之前加载,否则类是不完整的。这就是为什么我们不能进行循环继承,因为类加载器不知道如何处理。