Java:动态加载外部类

Java:动态加载外部类,java,classpath,classloader,Java,Classpath,Classloader,我正在编写一个将加载Java脚本的应用程序。我目前有一个GUI,它利用JFileChooser允许用户从机器上选择脚本。脚本文件可以在任何地方。它不在类路径上。只有一个文件对象来表示该脚本文件,如何获得它的类表示 我知道加载一个类需要它的二进制名称,所以.this.format中的。然而,问题是,我不知道脚本作者可能是如何将其打包的。例如,在开发脚本文件时,他/她可能会将脚本文件放在包foo.bar中。下载此脚本并将其放入文档(即,不在foo/bar中)后,如果不知道脚本已打包在foo.bar中

我正在编写一个将加载Java脚本的应用程序。我目前有一个GUI,它利用
JFileChooser
允许用户从机器上选择脚本。脚本文件可以在任何地方。它不在类路径上。只有一个
文件
对象来表示该脚本文件,如何获得它的
表示

我知道加载一个类需要它的二进制名称,所以.this.format中的
。然而,问题是,我不知道脚本作者可能是如何将其打包的。例如,在开发脚本文件时,他/她可能会将脚本文件放在包
foo.bar
中。下载此脚本并将其放入文档(即,不在
foo/bar
中)后,如果不知道脚本已打包在
foo.bar
中,则无法加载脚本。如果类名是
Test
,我尝试创建一个
URLClassLoader
,通过执行
newurlclassloader(newurl[]{newurl(scriptFile.toURI().toURL())}
classLoader.loadClass(“Test”)
来指向脚本文件,我将得到一个异常,说明该类的名称错误,正确的名称是
foo.bar.Test
。但我怎么能提前知道呢

这就是我现在拥有的:

public class ScriptClassLoader extends URLClassLoader {

    private final File script;

    public ScriptClassLoader(File script) throws MalformedURLException {
        super(new URL[] { script.toURI().toURL() });
        this.script = script;
    }

    public Class<?> load() throws ClassNotFoundException {
        String fileName = script.getName();
        String className = fileName.substring(0, fileName.indexOf(".class"));
        return loadClass(className);
    }
}
公共类ScriptClassLoader扩展了URLClassLoader{
私有最终文件脚本;
公共ScriptClassLoader(文件脚本)引发畸形的异常{
超级(新URL[]{script.toURI().toURL()});
this.script=脚本;
}
public Class load()引发ClassNotFoundException{
字符串文件名=script.getName();
String className=fileName.substring(0,fileName.indexOf(“.class”);
返回loadClass(className);
}
}

人们如何在运行时加载不属于程序类路径的脚本,并且类的二进制名称未知?

如果您只需要从给定的.class文件加载类,无论这些类如何命名,您都可以自己加载数据,然后调用ClassLoader的
defineClass()
方法:

RandomAccessFile raf = new RandomAccessFile(script, "r");
try {
    byte[] classData = new byte[(int) raf.length()];
    raf.readFully(classData);
    return super.defineClass(null, classData, 0, classData.length);
} finally {
    raf.close();
}

这绝不是一个解决方案,但是您可以捕获抛出的异常,读取正确的名称,然后再次执行读取操作。是的,它很便宜,但这是我读到《你》杂志的第一分钟就想到的第一件事。从积极的方面来看,这表明以正确的方式这样做是可能的。还有,请发一封邮件。我也想过这个,但那感觉太便宜了。如果没有更优雅的解决方案,我可能会这样做。实际上有很多解决方案,请参见和初学者。在这种情况下,
ScriptClassLoader
甚至不需要扩展
URLClassLoader
——它可以直接从
ClassLoader
继承。如果主脚本文件引用其他脚本文件,这将如何工作?如果我在
foo.bar
中有
MainScript
,并且它在
foo.bar.other
中引用了
SomeOtherScriptClass
,如果我只加载
MainScript
,该方法还能工作吗?或者,当脚本的执行到达使用
SomeOtherScriptClass
类中的方法的代码时,我是否会得到
NodeFoundError
?@MartinTuskevicius来解析对其他类的未知引用JVM将调用类加载器的
loadClass()
方法。您必须实现它,以便它在
foo/bar/other
或当前目录中或您喜欢的任何位置查找
SomeOtherScriptClass.class
。如果不将.class文件放置在预期的位置,那么这就是您要付出的代价。