如何加载与当前类不在同一jar存档中的类?

时间:2011-08-31 10:32:43

标签: java jar classloader java-compiler-api

情况:

我正在制作一个用于绘制算法时间复杂度的模拟器。学生可以添加加载自己的.java文件来运行它。 我的程序编译(使用'JavaCompiler').java文件。然后它尝试加载.class文件:

loadedClass = loadClass("customAlgorithms."+this.getClassName()+"");

在Eclipse中运行我的程序时,一切正常,学生可以完美地使用该程序。

问题:

然后我将项目导出到可执行jar文件中。编译部分仍然有效但加载类失败,因为它在里面搜索jar文件。

我想知道为什么我不能这样做:(改变。用/)

loadedClass = loadClass("customAlgorithms/"+this.getClassName()+"");

有哪些选择?这就是我能想到的:

  • 将已编译的.class文件添加到当前运行的.jar文件中。这甚至可以工作吗?

    我知道可以编辑jar存档。但这可以在运行时运行而无需重新启动程序吗?

  • 使用'loadClass()'的其他方式?这样我就可以加载一个未包含在我的jar文件中的类文件

还有其他想法吗?

3 个答案:

答案 0 :(得分:3)

Java通过ClassLoaders加载类。当您启动JVM时,您必须告诉JVM它的“类路径”,即类的文件夹或jar文件列表。 JVM将创建一个ClassLoader(通常是URLClassLoader的子类),并为此ClassLoader提供文件夹和jar文件的列表,以便类加载器能够加载该类。

在您的应用程序中,当您编译java源文件时,它会生成一个保存在某处的类文件。可能在eclipse中,保存类文件的文件夹是包含在类路径中的文件夹,以便JVM能够找到该类。

当您将项目导出到正在运行的jar文件时,可能会启动JVM,其类路径中只包含该JAR文件,因此它不会搜索已编译类的任何其他位置。

您有几种方法可以解决此问题。按复杂程度递增:

  1. 不要将jar作为可执行jar启动,而是使用.bat / .sh或任何其他可以配置类路径的java运行器,将特定文件夹添加到类路径中,将java源文件编译到该文件夹
  2. 编译java文件时,创建一个文件夹并创建指向该文件夹的URLClassLoader的新实例。将java文件编译到该文件夹​​。然后使用该URLCLassLoader加载已编译的类。
  3. 将java源代码编译为RAM,例如编译为字节数组,并实现一个自定义类加载器,它将返回该字节数组而不是从磁盘加载。
  4. 解决方案1非常简单,但有它的缺点:如果没有再次运行整个程序,将无法重新加载已编译的java文件(一旦类加载到类加载器中,它就无法再次加载,除非使用超出此问题范围的代理程序),它要求程序写入磁盘,这意味着权限等。

    解决方案2及其演变只是RAM更优雅,但更复杂:从类加载器加载单个类不同于整个应用程序其余部分使用的类是很棘手的,你可能会得到奇怪的类异常(如ClassCastExceptions,ClassNotFoundException等..)由于类加载器之间不匹配。

答案 1 :(得分:1)

您可以使用ClassLoader defineClass method。它受到保护,但应该没有问题。

如果该方法受到保护是一个问题,可能在互联网的某个地方你可以定义一个自由可用的自定义子类。

答案 2 :(得分:1)

您必须创建另一个类加载器,例如URLClassLoader并从中加载该类。