编译了一个类,但它在哪里?

时间:2011-10-15 22:43:11

标签: java classloader dynamic-compilation

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

我正在关注这段代码: 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之前,它运行良好。我很困惑,因为我似乎并没有从片段中删除一些重要内容:所以,这个类已经编译但是它已经去了哪里?

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

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

1 个答案:

答案 0 :(得分:2)

您切割的一件重要事情是所有错误输出和诊断信息。你永远不会知道出了什么问题。但是,一切看起来都正确。您的问题很可能就是您没有向编译器发送任何选项,因此它会将类文件写到任何地方(当前工作目录是默认值,我相信),这可能不在您的classpath,尤其是在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. 从当前目录成功加载新编译的类,因为它位于类路径上。