Java:如何将存储为byte[]的类加载到JVM中?

Java:如何将存储为byte[]的类加载到JVM中?,java,classloader,Java,Classloader,如果将整个.class文件序列化为字节[],并且假设类的名称已知(与字节[]一起传递),那么如何转换字节[]->class->然后将其加载到JVM中,以便我以后可以通过调用class.forName()来使用它 注意: 我这样做是因为我将.class发送到了另一台主机,而主机的JVM不知道这个.class。扩展类加载器,然后实现必要的调用以获取方法中的字节[]。相反,您可以在findClass()中执行此操作。因此,您将在开始时加载这个类加载器,或者在需要通过数组定义类时使用它 public c

如果将整个.class文件序列化为字节[],并且假设类的名称已知(与字节[]一起传递),那么如何转换字节[]->class->然后将其加载到JVM中,以便我以后可以通过调用class.forName()来使用它

注意:
我这样做是因为我将.class发送到了另一台主机,而主机的JVM不知道这个.class。

扩展
类加载器
,然后实现必要的调用以获取方法
中的
字节[]
。相反,您可以在
findClass()
中执行此操作。因此,您将在开始时加载这个类加载器,或者在需要通过数组定义类时使用它

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);
    }

}

使用

中的defineClass(String,byte[],int,int)方法好的,下面是我所做的:

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;
  }
}

实际上,我现在在一个测试中使用了类似的方法,将一组类定义作为byte[]提供给类加载器:

  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);
    }

  }
公共静态类ByteClassLoader扩展URLClassLoader{
私人最终地图;
公共字节类加载器(URL[]URL,类加载器父类,映射extraClassDefs){
超级(URL,父级);
this.extraClassDefs=新HashMap(extraClassDefs);
}
@凌驾
受保护类findClass(最终字符串名称)引发ClassNotFoundException{
byte[]classBytes=this.extraClassDefs.remove(名称);
if(classBytes!=null){
返回defineClass(名称,classBytes,0,classBytes.length);
}
返回super.findClass(名称);
}
}

Alex的答案是正确的,但如果类之间存在继承关系,则需要确保首先加载父类。否则类加载器将无法定义它。

Alex,但是如果2.class相互依赖呢?它还能用吗?可能不行。您可能应该发送(例如)一个JAR文件,而不是一系列单独的.class文件。@ShaChris23-当然,为什么不发送呢@Stephen C-这似乎是Java类加载器功能的有限视图。为什么你说可能不呢?我认为这样做是为了阻止随机代码在系统/默认类加载器上调用
defineClass
。这有可能危及安全性,通常会导致非常奇怪的事情发生。最好只在自定义类加载器上允许这样做。真的吗?我认为这是一个链接问题,而不是一个类定义问题。类不需要按正确的顺序定义,否则类中就不能有循环依赖关系。例如,Class.getName()返回一个字符串,但String.getClass()返回一个类。此外,这两个类都有Object的父类,但Object.toString()和Object.getClass()分别返回String和Class。如果你说的是真的,那么加载这些类的顺序就不正确了。@Kidburla这是因为JVM在需要类的时候加载它们,所以你可以在不需要加载字符串的情况下加载类,当你调用
getName
时,字符串将被加载。但是,超级类/接口需要在加载类时或之前加载,否则类是不完整的。这就是为什么我们不能有循环继承,因为类加载器不知道如何处理它。很抱歉,由于对已接受答案的评论,我将“继承”误读为“依赖”。@oʇoʇǝızuǝ之所以不能拥有循环继承,是因为它在逻辑上是不可能的,而不是因为加载它会有困难。超级类/接口不需要在加载类之前加载,因为这也会导致逻辑上的不可能性:除非先加载类,否则您不知道超级是什么,因此无法在加载类之前加载超级。