加载外部 .class 文件

要加载一个类,我们首先需要定义它。该类由 ClassLoader 定义。只有一个问题,Oracle 没有使用此功能编写 ClassLoader 的代码。要定义类,我们需要访问名为 defineClass() 的方法,这是 ClassLoader 的私有方法。

要访问它,我们要做的是创建一个新类 ByteClassLoader,并将其扩展到 ClassLoader。现在我们已经将类扩展到了 ClassLoader,我们可以访问 ClassLoader 的私有方法。为了使 defineClass() 可用,我们将创建一个新方法,它将像私有 defineClass() 方法的镜像一样。要调用私有方法,我们需要类名 name,类字节,classBytes,第一个字节的偏移量,这将是 0 因为 classBytes‘数据从 classBytes[0] 开始,而最后一个字节的偏移量将是 classBytes.lenght,因为它代表数据的大小,这将是最后的偏移量。

public class ByteClassLoader extends ClassLoader {

    public Class<?> defineClass(String name, byte[] classBytes) {
        return defineClass(name, classBytes, 0, classBytes.length);
    }

}

现在,我们有一个公共的 defineClass() 方法。可以通过将类的名称和类字节作为参数传递来调用它。

假设我们在包装中提到了名为 MyClass 的类……

要调用该方法,我们需要类字节,因此我们使用 Paths.get() 方法创建一个 Path 对象来表示我们的类路径,并将二进制类的路径作为参数传递。现在,我们可以使用 Files.readAllBytes(path) 获取类字节。所以我们创建了一个 ByteClassLoader 实例并使用我们创建的方法 defineClass()。我们已经有了类字节但是为了调用我们的方法,我们还需要类名,它由包名称(点)给出了类规范名称,在本例中为 stackoverflow.MyClass

Path path = Paths.get("MyClass.class");

ByteClassLoader loader = new ByteClassLoader();
loader.defineClass("stackoverflow.MyClass", Files.readAllBytes(path);

注意defineClass() 方法返回 Class<?> 对象。如果需要,你可以保存它。

要加载类,我们只需调用 loadClass() 并传递类名。这个方法可以抛出一个 ClassNotFoundException 所以我们需要使用 try cath 块

try{
    loader.loadClass("stackoverflow.MyClass");
} catch(ClassNotFoundException e){
    e.printStackTrace();
}