【问题标题】:Compiled a class, but where is it?编译了一个类,但它在哪里?
【发布时间】:2011-10-15 22:43:10
【问题描述】:

我不是 Java 专家,我对编译和运行动态生成代码的整个概念还很陌生,这在其他语言中非常简单,尤其是 Javascript 和 PHP 等脚本语言。

我正在关注这个 sn-p 代码: http://www.java2s.com/Code/Java/JDK-6/CompilingfromMemory.htm 我做了这样的事情:

private final String = "GeneratedClass_" + Long.toHexString(random.nextLong());
private Method compileCode(String code) {
    JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
    if (compiler == null) return null;

    DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<JavaFileObject>();

    JavaFileObject source = new JavaSource(className, code);
    Iterable<? extends JavaFileObject> compilationUnits = Arrays.asList(source);
    CompilationTask task = compiler.getTask(null, null, diagnostics, null, null, compilationUnits);

    if (!task.call()) return null;
    try {
        return Class.forName(className).getDeclaredMethods()[0];
    } catch (ClassNotFoundException e) {}
    return null;
}

private class JavaSource extends SimpleJavaFileObject {
    final String code;
    JavaSource(String name, String code) {
        super(URI.create("string:///" + name.replace('.','/') + Kind.SOURCE.extension),Kind.SOURCE);
        this.code = code;
    }

    @Override
    public CharSequence getCharContent(boolean ignoreEncodingErrors) {return code;}
}

想象一下字符串代码是这样的

"public class GeneratedClass_65ce701239c32ce0 {
    public String hello() {
        return "Hello, world!";
    }
}"

在抛出 ClassNotFoundException 的 Class.forName 之前它运行良好。我很困惑,因为我似乎没有从 sn-p 中删除一些重要的东西:所以,这个类已经编译了,但是它去哪儿了?

我读过一些关于使用不同类加载器的文章,但是,就像我说的,我对所有这些东西都很陌生,我不知道去哪里以及如何使用它,以及我应该如何定义自己的类加载器的扩展。 我唯一知道的是,一切对我来说似乎都很复杂......

在 Windows 7 和 JDK 1.7 中使用 Eclipse Indigo。

【问题讨论】:

  • 在 Java 中动态编译代码是一个相当高级的话题,我很惊讶您在还是 Java 初学者的同时就觉得需要它。你到底想做什么?可能有更好的方法,不涉及在运行时编译。
  • 其实我是在尝试移植一个 Javascript“类”来动态生成字符串和更一般的文档,并且它通过动态生成返回字符串的函数来设法做到这一点。它在 Javascript 中就像一个魅力,我成功地将它移植到 PHP 中,所以我也想尝试将它移植到 Java 中。我试图想象一些不同的东西,但这意味着......好吧,创建我自己的编译器......

标签: java classloader dynamic-compilation


【解决方案1】:

您删除的一个重要内容是所有错误输出和诊断信息。你永远不会知道是否出了什么问题。然而,一切看起来都是正确的。您的问题很可能只是您没有向编译器发送任何选项,因此它会将类文件写入任何感觉的位置(我相信当前工作目录是默认目录),这可能不在您的类路径,尤其是在 IDE 中。尝试从命令行运行它以向自己证明它有效。这应该有效:

mkdir tmp
javac -d tmp <path your main class .java file>
java -cp .;tmp <your main class name>

如果您不熟悉命令行工具,javac 的参数必须是 .java 文件的文件系统路径,java 的参数需要以 .-分隔,完全限定的类名,例如 com.foo.Main。这样做应该:

  1. 将您的类编译到 tmp 目录。
  2. 将动态生成的类写入当前目录。
  3. 成功从当前目录加载新编译的类,因为它在类路径中。

【讨论】:

  • 我明白你的意思,它很有帮助,但我担心它比这更复杂,因为该项目具有来自另一个项目的依赖项 - 实际创建代码并调用编译器的项目,顺便说一句。我注意到生成的 .class 文件在项目主目录中,而主类当然在 /bin 下。我想我可以找到一种方法来检索它并使用ClassLoader 加载它。如果我错了,请纠正我。
  • 是的,创建另一个 ClassLoader 来加载您的类将是另一种方法,但如果您没有正确创建和/或使用它,您仍然会遇到类路径问题。主要的是你需要确保你总是知道你的类文件在哪里,并计划如何加载它们。你不能只是把东西写出来就指望它神奇地起作用。
猜你喜欢
  • 2012-07-05
  • 2017-02-11
  • 2021-12-29
  • 2013-03-03
  • 2017-05-11
  • 1970-01-01
  • 2020-06-03
  • 1970-01-01
  • 2011-10-01
相关资源
最近更新 更多