代码之家  ›  专栏  ›  技术社区  ›  ihavenoidea

实例化运行时创建的类[重复]

  •  1
  • ihavenoidea  · 技术社区  · 6 年前

    (这个问题和我见过的许多问题相似,但大多数问题都不够具体)

    背景:

    我的问题是,如何获得它,以便客户机(使用我编译的程序)可以将这个java文件(它扩展了我的InterfaceExample)保存在他们计算机上的任何位置,让我的程序编译它(不说“找不到符号:InterfaceExample”),然后加载它并调用doSomething()方法?

    我一直在看Q&A使用了反射或类加载器,并且几乎描述了如何编译它,但是没有一个对我足够详细/我不完全理解它们。

    0 回复  |  直到 8 年前
        1
  •  69
  •   MadProgrammer    5 年前

    JavaCompiler

    以下是基于JavaDocs中给出的示例

    File testcompile package 名称要求)和 文件

    package inlinecompiler;
    
    import java.io.File;
    import java.io.FileWriter;
    import java.io.IOException;
    import java.io.Writer;
    import java.net.URL;
    import java.net.URLClassLoader;
    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.List;
    import javax.tools.Diagnostic;
    import javax.tools.DiagnosticCollector;
    import javax.tools.JavaCompiler;
    import javax.tools.JavaFileObject;
    import javax.tools.StandardJavaFileManager;
    import javax.tools.ToolProvider;
    
    public class InlineCompiler {
    
        public static void main(String[] args) {
            StringBuilder sb = new StringBuilder(64);
            sb.append("package testcompile;\n");
            sb.append("public class HelloWorld implements inlinecompiler.InlineCompiler.DoStuff {\n");
            sb.append("    public void doStuff() {\n");
            sb.append("        System.out.println(\"Hello world\");\n");
            sb.append("    }\n");
            sb.append("}\n");
    
            File helloWorldJava = new File("testcompile/HelloWorld.java");
            if (helloWorldJava.getParentFile().exists() || helloWorldJava.getParentFile().mkdirs()) {
    
                try {
                    Writer writer = null;
                    try {
                        writer = new FileWriter(helloWorldJava);
                        writer.write(sb.toString());
                        writer.flush();
                    } finally {
                        try {
                            writer.close();
                        } catch (Exception e) {
                        }
                    }
    
                    /** Compilation Requirements *********************************************************************************************/
                    DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<JavaFileObject>();
                    JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
                    StandardJavaFileManager fileManager = compiler.getStandardFileManager(diagnostics, null, null);
    
                    // This sets up the class path that the compiler will use.
                    // I've added the .jar file that contains the DoStuff interface within in it...
                    List<String> optionList = new ArrayList<String>();
                    optionList.add("-classpath");
                    optionList.add(System.getProperty("java.class.path") + File.pathSeparator + "dist/InlineCompiler.jar");
    
                    Iterable<? extends JavaFileObject> compilationUnit
                            = fileManager.getJavaFileObjectsFromFiles(Arrays.asList(helloWorldJava));
                    JavaCompiler.CompilationTask task = compiler.getTask(
                        null, 
                        fileManager, 
                        diagnostics, 
                        optionList, 
                        null, 
                        compilationUnit);
                    /********************************************************************************************* Compilation Requirements **/
                    if (task.call()) {
                        /** Load and execute *************************************************************************************************/
                        System.out.println("Yipe");
                        // Create a new custom class loader, pointing to the directory that contains the compiled
                        // classes, this should point to the top of the package structure!
                        URLClassLoader classLoader = new URLClassLoader(new URL[]{new File("./").toURI().toURL()});
                        // Load the class from the classloader by name....
                        Class<?> loadedClass = classLoader.loadClass("testcompile.HelloWorld");
                        // Create a new instance...
                        Object obj = loadedClass.newInstance();
                        // Santity check
                        if (obj instanceof DoStuff) {
                            // Cast to the DoStuff interface
                            DoStuff stuffToDo = (DoStuff)obj;
                            // Run it baby
                            stuffToDo.doStuff();
                        }
                        /************************************************************************************************* Load and execute **/
                    } else {
                        for (Diagnostic<? extends JavaFileObject> diagnostic : diagnostics.getDiagnostics()) {
                            System.out.format("Error on line %d in %s%n",
                                    diagnostic.getLineNumber(),
                                    diagnostic.getSource().toUri());
                        }
                    }
                    fileManager.close();
                } catch (IOException | ClassNotFoundException | InstantiationException | IllegalAccessException exp) {
                    exp.printStackTrace();
                }
            }
        }
    
        public static interface DoStuff {
    
            public void doStuff();
        }
    
    }
    

    现在更新到包括为编译器提供类路径,以及加载和执行已编译的类!

        2
  •  34
  •   Art Licis    6 年前

    Java Runtime Compiler

    例如

     // dynamically you can call
     String className = "mypackage.MyClass";
     String javaCode = "package mypackage;\n" +
                      "public class MyClass implements Runnable {\n" +
                      "    public void run() {\n" +
                      "        System.out.println(\"Hello World\");\n" +
                      "    }\n" +
                      "}\n";
     Class aClass = CompilerUtils.CACHED_COMPILER.loadFromJava(className, javaCode);
     Runnable runner = (Runnable) aClass.newInstance();
     runner.run();