web-dev-qa-db-ja.com

Java:byte []として格納されているクラスをJVMにロードする方法は?

.classファイル全体をbyte []に​​シリアル化し、クラスの名前がわかっている(byte []とともに渡される)と仮定した場合、byte []-> Class->をどのように変換し、それをにロードしますか。後でClass.forName()を呼び出して使用できるようにJVM?

注:これを行っているのは、.classを別のホストに送信し、ホストのJVMがこの.classを認識していないためです。

23
sivabudh

私は実際にテストでこのようなものを使用して、クラス定義のセットを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);
    }

  }
26
Alex Miller

ClassLoader からdefineClass(String、byte []、int、int)メソッドを使用します

9
Matt

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

}
_
4
Jé Queue

さて、これが私がしたことです:

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

Alexの答えは正しいですが、クラス間に継承関係がある場合は、最初に親クラスをロードする必要があります。そうしないと、クラスローダーはそれを定義できません。

0
marting