• java动态编译


    一、使用 JavaCompiler 接口来编译 java 源程序(最简单的)

    使用 Java API 来编译 Java 源程式有非常多方法,目前让我们来看一种最简单的方法,通过 JavaCompiler 进行编译。

    我们能通过 ToolProvider 类的静态方法 getSystemJavaCompiler 来得到一个 JavaCompiler 接 口的实例。


    JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();


    JavaCompiler 中最核心的方法是 run。通过这个方法能编译 java 源程序。这个方法有 3 个固 定参数和 1 个可变参数(可变参数是从 Jave SE5 开始提供的一个新的参数类型,用 type... argu 表 示)。前 3 个参数分别用来为 java 编译器提供参数、得到 Java 编译器的输出信息及接收编译器的 错误信息,后面的可变参数能传入一个或多个 Java 源程式文件。如果 run 编译成功,返回 0。

    int run(InputStream in, OutputStream out, OutputStream err, String... arguments)

    如果前 3 个参数传入的是 null,那么 run 方法将以标准的输入、输出代替,即 System.in、 System.out 和 System.err。如果我们要编译一个 hello.java 文件,并将使用标准输入输出,run 的使用方法如下:

    int results = tool.run(null, null, null, "Hello.java");

    完整代码如下(用的是 eclipse 工具)


    package com.dongtai.demo; 

    import java.io.BufferedReader; 
    import java.io.IOException; 
    import java.io.InputStream; 
    import java.io.InputStreamReader; 

    import javax.tools.JavaCompiler; 
    import javax.tools.ToolProvider; 

    public class DynamicCompileTest { 
        public static void main(String[] args) throws IOException { 
            // 编译程序 
            JavaCompiler javaCompiler = ToolProvider.getSystemJavaCompiler(); 
            int result = javaCompiler.run(null, null, null, "-d","./temp/","./temp/com/Hello.java"); 
            System.out.println( result == 0 ? "恭喜编译成功" : "对不起编译失败"); 
             
            // 运行程序 
            Runtime run = Runtime.getRuntime(); 
            Process process = run.exec("java -cp ./temp temp/com/Hello"); 
            InputStream in = process.getInputStream(); 
            BufferedReader reader = new BufferedReader(new InputStreamReader(in)); 
            String info  = ""; 
            while ((info = reader.readLine()) != null) { 
                System.out.println(info); 
                     
            } 
        } 

    二、使用 StandardJavaFileManager 编译 Java 源程序

    在第一部分我们讨论调用 java 编译器的最容易的方法。这种方法能非常好地工作,但他确不 能更有效地得到我们所需要的信息,如标准的输入、输出信息。而在 Java SE6 中最佳的方法是使 用 StandardJavaFileManager 类。这个类能非常好地控制输入、输出,并且能通过 DiagnosticListener 得到诊断信息,而 DiagnosticCollector 类就是 listener 的实现。

    使用 StandardJavaFileManager 需要两步。首先建立一个 DiagnosticCollector 实例及通过 JavaCompiler 的 getStandardFileManager()方法得到一个 StandardFileManager 对象。最后通过 CompilationTask 中的 call 方法编译源程序

    每个类的具体方法参数可以查看 jase6 API 文档。上面有很详细的解释


    package com.dongtai.demo;

    import java.io.BufferedReader;
    import java.io.File;
    import java.io.FileWriter;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.InputStreamReader;
    import java.util.Arrays;

    import javax.tools.JavaCompiler;
    import javax.tools.JavaCompiler.CompilationTask;
    import javax.tools.StandardJavaFileManager;
    import javax.tools.ToolProvider;

    public class DynamicCompileTest {
        public static void main(String[] args) throws IOException{
            // 1.创建需要动态编译的代码字符串
            String nr = " "; //回车
            String source = "package temp.com; " + nr +
                    " public class  Hello{" + nr + 
                        " public static void main (String[] args){" + nr + 
                            " System.out.println("HelloWorld! 1");" + nr +
                        " }" + nr +
                    " }";
            // 2.将欲动态编译的代码写入文件中 1.创建临时目录 2.写入临时文件目录
            File dir = new File(System.getProperty("user.dir") + "/temp"); //临时目录
            // 如果 emp 不存在 就创建
            if (!dir.exists()) {
                dir.mkdir();
            }
            FileWriter writer = new FileWriter(new File(dir,"Hello.java"));
            writer.write(source);
            writer.flush();
            writer.close();
            
            // 3.取得当前系统的编译器
            JavaCompiler javaCompiler = ToolProvider.getSystemJavaCompiler();
            // 4.获取一个文件管理器
            StandardJavaFileManager javaFileManager = javaCompiler.getStandardFileManager(null, null, null);
            // 5.文件管理器根与文件连接起来
            Iterable it = javaFileManager.getJavaFileObjects(new File(dir,"Hello.java"));
            // 6.创建编译任务
            CompilationTask task = javaCompiler.getTask(null, javaFileManager, null, Arrays.asList("-d", "./temp"), null, it);
            // 7.执行编译
            task.call();
            javaFileManager.close();
            
            // 8.运行程序
            Runtime run = Runtime.getRuntime();
            Process process = run.exec("java -cp ./temp temp/com/Hello");
            InputStream in = process.getInputStream();
            BufferedReader reader = new BufferedReader(new InputStreamReader(in));
            String info  = "";
            while ((info = reader.readLine()) != null) {
                System.out.println(info);
                
            }
        }
    }

    三、从内存中动态编译 java 程序

    JavaCompiler 不仅能编译硬盘上的 Java 文件,而且还能编译内存中的 Java 代码,然后使 
    用 reflection 来运行他们。我们能编写一个类,通过这个类能输入 Java 原始码。一但建立这个对
    象,你能向其中输入任意的 Java 代码,然后编译和运行。


    package com.dongtai.demo;
    import java.io.BufferedReader;
    import java.io.File;
    import java.io.FileWriter;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.InputStreamReader;
    import java.io.PrintWriter;
    import java.io.StringWriter;
    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;
    import java.net.URI;
    import java.net.URL;
    import java.net.URLClassLoader;
    import java.util.Arrays;

    import javax.tools.JavaCompiler;
    import javax.tools.JavaCompiler.CompilationTask;
    import javax.tools.JavaFileObject;
    import javax.tools.StandardJavaFileManager;
    import javax.tools.ToolProvider;

    public class DynamicCompileTest {
        public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, InstantiationException{
            
            /*
             * 编译内存中的java代码
             * */
            // 1.将代码写入内存中
            StringWriter writer = new StringWriter(); // 内存字符串输出流
            PrintWriter out = new PrintWriter(writer);
            out.println("package com.dongtai.hello;");
            out.println("public class Hello{");
            out.println("public static void main(String[] args){");
            out.println("System.out.println("HelloWorld! 2");");
            out.println("}");
            out.println("}");
            out.flush();
            out.close();
            
            // 2.开始编译
            JavaCompiler javaCompiler = ToolProvider.getSystemJavaCompiler();
            JavaFileObject fileObject = new JavaStringObject("Hello", writer.toString());
            CompilationTask task = javaCompiler.getTask(null, null, null, Arrays.asList("-d","./bin"), null, Arrays.asList(fileObject));
            boolean success = task.call();
            if (!success) {
                System.out.println("编译失败");
            }else{
                System.out.println("编译成功");
            }
            URL[] urls = new URL[]{new URL("file:/" + "./bin/")};
            URLClassLoader classLoader = new URLClassLoader(urls);
            Class classl = classLoader.loadClass("com.dongtai.hello.Hello");
            Method method = classl.getDeclaredMethod("main", String[].class);
            String[] argsl = {null};
            method.invoke(classl.newInstance(), argsl);
        
        }
    }

    引用至:http://www.cnblogs.com/snake-hand/p/3159694.html

  • 相关阅读:
    忽略大小写的RegularExpressionValidator
    Outlook 2010 “加载项执行错误。调用“Microsoft Exchange 加载项”加载项时,在“IDTExtensibility2”接口回调“OnConnection”期间,Outlook 出现故障”问题
    选择排序——算法系列
    代码杂记32
    数据库系统原理
    C#中的委托与事件
    C#多线程
    冒泡排序——算法系列
    快速排序——算法系列
    递归算法——猴子吃桃
  • 原文地址:https://www.cnblogs.com/zxf330301/p/5533572.html
Copyright © 2020-2023  润新知