To load a class we first need to define it. The class is defined by the ClassLoader
. There's just one problem, Oracle didn't write the ClassLoader
's code with this feature available. To define the class we will need to access a method named defineClass()
which is a private method of the ClassLoader
.
To access it, what we will do is create a new class, ByteClassLoader
, and extend it to ClassLoader
. Now that we have extended our class to ClassLoader
, we can access the ClassLoader
's private methods. To make defineClass()
available, we will create a new method that will act like a mirror for the private defineClass()
method. To call the private method we will need the class name, name
, the class bytes, classBytes
, the first byte's offset, which will be 0
because classBytes
' data starts at classBytes[0]
, and the last byte's offset, which will be classBytes.lenght
because it represents the size of the data, which will be the last offset.
public class ByteClassLoader extends ClassLoader {
public Class<?> defineClass(String name, byte[] classBytes) {
return defineClass(name, classBytes, 0, classBytes.length);
}
}
Now, we have a public defineClass()
method. It can be called by passing the name of the class and the class bytes as arguments.
Let's say we have class named MyClass
in the package stackoverflow
...
To call the method we need the class bytes so we create a Path
object representing our class' path by using the Paths.get()
method and passing the path of the binary class as an argument. Now, we can get the class bytes with Files.readAllBytes(path)
. So we create a ByteClassLoader
instance and use the method we created, defineClass()
. We already have the class bytes but to call our method we also need the class name which is given by the package name (dot) the class canonical name, in this case stackoverflow.MyClass
.
Path path = Paths.get("MyClass.class");
ByteClassLoader loader = new ByteClassLoader();
loader.defineClass("stackoverflow.MyClass", Files.readAllBytes(path);
Note: The defineClass()
method returns a Class<?>
object. You can save it if you want.
To load the class, we just call loadClass()
and pass the class name. This method can throw an ClassNotFoundException
so we need to use a try cath block
try{
loader.loadClass("stackoverflow.MyClass");
} catch(ClassNotFoundException e){
e.printStackTrace();
}