`

Java 动态编译

    博客分类:
  • 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 工具)

 

[java] view plaincopy
 
  1. package com.dongtai.demo;  
  2.   
  3. import java.io.BufferedReader;  
  4. import java.io.IOException;  
  5. import java.io.InputStream;  
  6. import java.io.InputStreamReader;  
  7.   
  8. import javax.tools.JavaCompiler;  
  9. import javax.tools.ToolProvider;  
  10.   
  11. public class DynamicCompileTest {  
  12.     public static void main(String[] args) throws IOException {  
  13.         // 编译程序  
  14.         JavaCompiler javaCompiler = ToolProvider.getSystemJavaCompiler();  
  15.         int result = javaCompiler.run(nullnullnull"-d","./temp/","./temp/com/Hello.java");  
  16.         System.out.println( result == 0 ? "恭喜编译成功" : "对不起编译失败");  
  17.           
  18.         // 运行程序  
  19.         Runtime run = Runtime.getRuntime();  
  20.         Process process = run.exec("java -cp ./temp temp/com/Hello");  
  21.         InputStream in = process.getInputStream();  
  22.         BufferedReader reader = new BufferedReader(new InputStreamReader(in));  
  23.         String info  = "";  
  24.         while ((info = reader.readLine()) != null) {  
  25.             System.out.println(info);  
  26.                   
  27.         }  
  28.     }  
  29. }  



 

 

二、使用 StandardJavaFileManager 编译 Java 源程序

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

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

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

 

[java] view plaincopy
 
  1. package com.dongtai.demo;  
  2.   
  3. import java.io.BufferedReader;  
  4. import java.io.File;  
  5. import java.io.FileWriter;  
  6. import java.io.IOException;  
  7. import java.io.InputStream;  
  8. import java.io.InputStreamReader;  
  9. import java.util.Arrays;  
  10.   
  11. import javax.tools.JavaCompiler;  
  12. import javax.tools.JavaCompiler.CompilationTask;  
  13. import javax.tools.StandardJavaFileManager;  
  14. import javax.tools.ToolProvider;  
  15.   
  16. public class DynamicCompileTest {  
  17.     public static void main(String[] args) throws IOException{  
  18.         // 1.创建需要动态编译的代码字符串  
  19.         String nr = "\r\n"//回车  
  20.         String source = "package temp.com; " + nr +  
  21.                 " public class  Hello{" + nr +   
  22.                     " public static void main (String[] args){" + nr +   
  23.                         " System.out.println(\"HelloWorld! 1\");" + nr +  
  24.                     " }" + nr +  
  25.                 " }";  
  26.         // 2.将欲动态编译的代码写入文件中 1.创建临时目录 2.写入临时文件目录  
  27.         File dir = new File(System.getProperty("user.dir") + "/temp"); //临时目录  
  28.         // 如果 \temp 不存在 就创建  
  29.         if (!dir.exists()) {  
  30.             dir.mkdir();  
  31.         }  
  32.         FileWriter writer = new FileWriter(new File(dir,"Hello.java"));  
  33.         writer.write(source);  
  34.         writer.flush();  
  35.         writer.close();  
  36.           
  37.         // 3.取得当前系统的编译器  
  38.         JavaCompiler javaCompiler = ToolProvider.getSystemJavaCompiler();  
  39.         // 4.获取一个文件管理器  
  40.         StandardJavaFileManager javaFileManager = javaCompiler.getStandardFileManager(nullnullnull);  
  41.         // 5.文件管理器根与文件连接起来  
  42.         Iterable it = javaFileManager.getJavaFileObjects(new File(dir,"Hello.java"));  
  43.         // 6.创建编译任务  
  44.         CompilationTask task = javaCompiler.getTask(null, javaFileManager, null, Arrays.asList("-d""./temp"), null, it);  
  45.         // 7.执行编译  
  46.         task.call();  
  47.         javaFileManager.close();  
  48.           
  49.         // 8.运行程序  
  50.         Runtime run = Runtime.getRuntime();  
  51.         Process process = run.exec("java -cp ./temp temp/com/Hello");  
  52.         InputStream in = process.getInputStream();  
  53.         BufferedReader reader = new BufferedReader(new InputStreamReader(in));  
  54.         String info  = "";  
  55.         while ((info = reader.readLine()) != null) {  
  56.             System.out.println(info);  
  57.               
  58.         }  
  59.     }  
  60. }  



 

 

 

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

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

 

 

[java] view plaincopy
 
  1. package com.dongtai.demo;  
  2. import java.io.BufferedReader;  
  3. import java.io.File;  
  4. import java.io.FileWriter;  
  5. import java.io.IOException;  
  6. import java.io.InputStream;  
  7. import java.io.InputStreamReader;  
  8. import java.io.PrintWriter;  
  9. import java.io.StringWriter;  
  10. import java.lang.reflect.InvocationTargetException;  
  11. import java.lang.reflect.Method;  
  12. import java.net.URI;  
  13. import java.net.URL;  
  14. import java.net.URLClassLoader;  
  15. import java.util.Arrays;  
  16.   
  17. import javax.tools.JavaCompiler;  
  18. import javax.tools.JavaCompiler.CompilationTask;  
  19. import javax.tools.JavaFileObject;  
  20. import javax.tools.StandardJavaFileManager;  
  21. import javax.tools.ToolProvider;  
  22.   
  23. public class DynamicCompileTest {  
  24.     public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, InstantiationException{  
  25.           
  26.         /* 
  27.          * 编译内存中的java代码 
  28.          * */  
  29.         // 1.将代码写入内存中  
  30.         StringWriter writer = new StringWriter(); // 内存字符串输出流  
  31.         PrintWriter out = new PrintWriter(writer);  
  32.         out.println("package com.dongtai.hello;");  
  33.         out.println("public class Hello{");  
  34.         out.println("public static void main(String[] args){");  
  35.         out.println("System.out.println(\"HelloWorld! 2\");");  
  36.         out.println("}");  
  37.         out.println("}");  
  38.         out.flush();  
  39.         out.close();  
  40.           
  41.         // 2.开始编译  
  42.         JavaCompiler javaCompiler = ToolProvider.getSystemJavaCompiler();  
  43.         JavaFileObject fileObject = new JavaStringObject("Hello", writer.toString());  
  44.         CompilationTask task = javaCompiler.getTask(nullnullnull, Arrays.asList("-d","./bin"), null, Arrays.asList(fileObject));  
  45.         boolean success = task.call();  
  46.         if (!success) {  
  47.             System.out.println("编译失败");  
  48.         }else{  
  49.             System.out.println("编译成功");  
  50.         }  
  51.         URL[] urls = new URL[]{new URL("file:/" + "./bin/")};  
  52.         URLClassLoader classLoader = new URLClassLoader(urls);  
  53.         Class classl = classLoader.loadClass("com.dongtai.hello.Hello");  
  54.         Method method = classl.getDeclaredMethod("main", String[].class);  
  55.         String[] argsl = {null};  
  56.         method.invoke(classl.newInstance(), argsl);  
  57.       
  58.     }  
  59. }  
分享到:
评论

相关推荐

    JavaCompiler --JDK6 API的简介(java动态编译)

    JavaCompiler --JDK6 API 的简介(java动态编译) JavaCompiler 是 Java 中的一个编译器接口,提供了编译 Java 源代码的功能。在 Java SE6 中,JavaCompiler 接口是 javax.tools 包的一部分,提供了标准的方式来...

    java动态编译指定java文件且将java文件生成jar

    在Java编程中,有时我们需要在运行时动态地编译源代码文件,并将其打包成可执行的JAR(Java Archive)文件。这样的需求通常出现在我们希望根据用户输入或特定条件生成并执行新的代码逻辑时。本教程将深入讲解如何...

    java动态编译java源文件

    Java动态编译指的是在程序运行时将Java源代码编译为字节码并加载到Java虚拟机(JVM)中的过程。这种技术在许多场景下非常有用,例如在开发环境中进行快速迭代、AOP(面向切面编程)或运行时代码生成等。Java的`javax...

    Java动态编译Java代码,运行在内存中,并执行

    添加动态执行的编译环境 options 是个集合,添加内容,字符集,classpath等 * 6.传入JavaFileObject的java文件,是个集合,创建JavaSourceObject实现这个接口,Kind.SOURCE.extension = '.java' * 7.创建任务并...

    java 动态编译.java文件,动态运行类

    在Java编程中,动态编译和运行类是一项重要的能力,特别是在需要实时更新代码或实现热部署的场景下。本文将深入探讨如何利用Java的API来动态编译.java源文件,并执行编译后的类。 首先,Java的`javac`命令行工具是...

    java动态编译 ,写了一个jsp在页面上编辑java代码,然后servlet动态编译并执行main方法

    Java动态编译是一种技术,允许程序在运行时将源代码转换为字节码并加载到JVM(Java虚拟机)中。这种能力使得Java应用程序能够根据需要编译和执行新的代码,增强了软件的灵活性和可扩展性。在给定的场景中,用户通过...

    Java 动态编译源码并调用

    Java 动态编译源码并调用是Java开发中的一种高级技巧,它允许程序在运行时根据需要编译和执行新的代码。这种能力在某些场景下非常有用,例如插件系统、元编程或者在运行时自动生成和执行特定逻辑。下面我们将详细...

    java 动态编译打包 动态编译可以用于实现动态代码生成、动态加载、插件化等功能

    Java 动态编译打包是Java开发中的一个重要技术,它允许程序在运行时生成和编译源代码,然后即时加载到应用程序中。这种技术在许多场景下都非常有用,例如实现动态代码生成、动态加载和插件化系统。下面将详细讨论...

    Java 动态编译小工具

    Java 动态编译小工具是一种实用的程序开发辅助工具,尤其在面对复杂或需要频繁迭代的项目时,它的价值尤为突出。这个工具的核心功能是能够在运行时动态编译Java源代码并将其加载到Java虚拟机(JVM)中,从而实现对...

    java 动态编译特性的展示工程勘误篇

    Java动态编译特性是Java平台一个非常强大的功能,它允许我们在程序运行时将源代码编译成字节码,然后直接加载到JVM中执行。这个特性极大地提升了Java的灵活性和适应性,使得我们可以实现一些在编译时无法确定的复杂...

    java 动态编译.java文件,动态运行类 _1.3

    在Java编程中,动态编译和运行类是一项重要的技术,特别是在需要实时更新代码或实现热部署的场景下。本文将详细讲解如何在Java中实现动态编译.java源代码文件并执行编译后的类。 首先,我们需要理解Java的编译过程...

    java 动态编译.java文件,动态运行类 _1.2

    1. **Java编译API:Javacompiler接口** Java提供了一个内置的`javax.tools.JavaCompiler`接口,它是Java工具接口(Java Tool API)的一部分,允许我们在程序中调用Javac编译器。要使用这个接口,首先需要引入`tools...

    Java类动态加载(一)——java源文件动态编译为class文件

    这篇博客“Java类动态加载(一)——java源文件动态编译为class文件”可能主要探讨了如何在运行时将Java源代码(.java)编译成对应的字节码文件(.class),并将其加载到Java虚拟机(JVM)中。以下是对这个主题的详细解析...

    JDK8 下 SpringBoot 应用动态编译 Java 源码并注入 Spring 容器

    SpringBoot 应用动态编译 Java 源码并注入 Spring 容器,实现动态修改接口和抽象类的实现。注意,项目以 Jar 包形式启动时要在命令行引入 tools.jar 的包,IDEA下可直接调试。 基于接口、抽象类实现不停机动态调整...

    利用Java的动态编译、动态加载结合EasyRules实现业务规则的动态性的项目源码

    利用Java的动态编译、动态加载结合EasyRules实现业务规则的动态性的项目源码,具体详情请查看相关博客https://blog.csdn.net/qq_31142553/article/details/85013989

    利用Java动态编译计算数学表达式

    后来考虑到这样编程的任务很重,时间有限 后来在网上搜搜,看到使用动态编译并使用反射机制 ,这样计算表达式的编程就容易多了. 前几天要做一个计算数学表达式的题目,本来计划使用解析表达式的方法来解析各种数学...

    java 动态编译.java文件,动态运行类 _1.1

    在Java编程环境中,有时我们需要在程序运行时动态地编译.java源代码文件并执行新编译的类。这种能力在诸如代码热更新、插件系统或者测试自动化等场景下非常有用。本文将深入探讨如何在Java中实现动态编译与运行。 ...

    JAVA反编译工具JAVA反编译工具JAVA反编译工具JAVA反编译工具JAVA反编译工具

    JAVA反编译工具JAVA反编译工具JAVA反编译工具JAVA反编译工具JAVA反编译工具JAVA反编译工具JAVA反编译工具JAVA反编译工具JAVA反编译工具JAVA反编译工具JAVA反编译工具JAVA反编译工具JAVA反编译工具JAVA反编译工具JAVA...

Global site tag (gtag.js) - Google Analytics