加载外部 .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();
}