一、使用JavaCompiler接口编译java源程序
我们可以通过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。
下面是利用java动态编译实现eval功能:
package com.flyoung; import java.io.File; import java.io.FileWriter; import java.io.PrintWriter; import java.lang.reflect.Method; import javax.tools.JavaCompiler; import javax.tools.ToolProvider; public class JavacTest { public JavacTest(){ } public static void eval(String str){ System.out.println(System.getProperty("user.dir"));//当前工作目录 String s = "public class Temp{" ; s+="\r\n"+" public static String call(String ss){ "; s+="\r\n"+" System.out.println(\""+str+"\"); "; s+="\r\n"+" return \"return_str\"; "; s+="\r\n"+" }"; s+="\r\n"+"}"; try{ File file = new File("Temp.java"); PrintWriter pw = new PrintWriter(new FileWriter(file)); //pw.println(s); //pw.write(s); pw.close(); //动态编译 JavaCompiler javac = ToolProvider.getSystemJavaCompiler(); int status = javac.run(null, null, null, "-d",System.getProperty("user.dir")+"/bin","Temp.java"); if(status!=0){ System.out.println("没有编译成功!"); } //动态执行 Class cls = Class.forName("Temp");//返回与带有给定字符串名的类 或接口相关联的 Class 对象。 Method method = cls.getDeclaredMethod("call", String.class);//返回一个 Method 对象,该对象反映此 Class 对象所表示的类或接口的指定已声明方法 String result= (String)method.invoke(null, str);//静态方法第一个参数可为null,第二个参数为实际传参 System.out.println(result); }catch(Exception e){ e.printStackTrace(); } } /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub JavacTest javacTest = new JavacTest(); javacTest.eval("input_str"); } }
二、使用StandardJavaFileManager编译java源程序
在Java SE6中最好的方法是使用StandardJavaFileManager类。这个类可以很好地控制输入、输出,并且可以通过DiagnosticListener得到诊断信息,而DiagnosticCollector类就是listener的实现。
使用StandardJavaFileManager需要两步。首先建立一个DiagnosticCollector实例以及通过 JavaCompiler的getStandardFileManager()方法得到一个StandardFileManager对象。最后通过 CompilationTask中的call方法编译源程序。
详细请看:http://doc.java.sun.com/DocWeb/api/javax.tools.JavaCompiler
示例:
package com.flyoung; import java.io.File; import java.io.FileWriter; import java.util.Arrays; import javax.tools.JavaCompiler; import javax.tools.StandardJavaFileManager; import javax.tools.ToolProvider; import javax.tools.JavaCompiler.CompilationTask; public class DynamicCompileTest { public static void main(String[] args) throws Exception { //1.创建需要动态编译的代码字符串 String nr="\r\n";//回车换行 String source="package com.flyoung.hello;"+nr+ " public class Hello{"+nr+ " public static void main(String[] args){"+nr+ " System.out.println(\"helloworld!\");"+nr+ "}"+nr+ "}" ; //2.将预动态编译的代码写入文件中1:创建临时目录 2:写入临时文件 File dir=new File(System.getProperty("user.dir")+"/temp");//临时目录 //如果/temp目录不存在创建temp目录 if(!dir.exists()){ dir.mkdir(); } FileWriter writer=new FileWriter(new File(dir,"Hello.java")); writer.write(source);//将字符串写入文件中 writer.flush(); writer.close(); //3:取得当前系统java编译器 JavaCompiler javaCompiler=ToolProvider.getSystemJavaCompiler(); //4:获取一个文件管理器StandardJavaFileManage 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); //执行编译 task.call(); javaFileManager.close(); } }
三、从内存中动态编译源程序
JavaCompiler 不仅能编译硬盘上的 Java 文件,而且还能编译内存中的 Java 代码,然后使用reflection来运行他们。
package com.flyoung; import java.io.IOException; import java.net.URI; import javax.tools.SimpleJavaFileObject; public class JavaStringObject extends SimpleJavaFileObject { private String code; public JavaStringObject(String name, String code) { //super(URI.create("string:///" + name.replace('.', '/') + Kind.SOURCE.extension), Kind.SOURCE); super(URI.create(name+".java"), Kind.SOURCE); this.code = code; } @Override public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException { return code; } }
package com.flyoung; import java.io.PrintWriter; import java.io.StringWriter; import java.lang.reflect.Method; import java.net.URL; import java.net.URLClassLoader; import java.util.Arrays; import javax.tools.JavaCompiler; import javax.tools.JavaFileObject; import javax.tools.ToolProvider; import javax.tools.JavaCompiler.CompilationTask; public class DynamicCompileTest { public static void main(String[] args) throws Exception { /* * 编译内存中的java代码 */ // 将代码写入内存中 StringWriter writer = new StringWriter();// 内存字符串输出流 PrintWriter out = new PrintWriter(writer); out.println("package com.flyoung.hello;"); out.println("public class Hello{"); out.println("public static void main(String[] args){"); out.println("System.out.println(\"helloworld!\");"); out.println("}"); out.println("}"); out.flush(); out.close(); // 开始编译 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("编译成功!"); //利用反射调用其中的main()方法 // Class class1=Class.forName("com.flyoung.hello.Hello"); //ClassLoader是自动去从当前工作目录下的classpath路径下去找 也就是bin目录下 //Class class1=ClassLoader.getSystemClassLoader().loadClass("com.flyoung.hello.Hello"); //利用URLClassLoader去实例化一个Class类 类文件可以放在任意位置,这样就很方便了 URL[] urls=new URL[]{new URL("file:/"+"./bin/")}; URLClassLoader classLoader=new URLClassLoader(urls); Class class1=classLoader.loadClass("com.flyoung.hello.Hello"); Method method=class1.getDeclaredMethod("main",String[].class); String[] args1={null}; method.invoke(class1.newInstance(),args1); } } }
相关推荐
同时,书中不仅完整地讲述了由Java SE 8所引入的新特性,例如对包含默认实现代码的接口方法所做的调用,还讲述了为支持类型注解及方法参数注解而对class文件格式所做的扩展,并阐明了class文件中各属性的含义,以及...
《Java虚拟机规范(Java SE 7版)》是Java领域最重要和最权威的著作之一,由Oracle官方发布,基于Java SE 7,对最新的Java虚拟机规范进行了完整且详细的讲解,是深度了解Java虚拟机实现细节的必读之作。由国内几位资深...
《Java核心技术系列:Java虚拟机规范(Java SE 8版)》由Oracle官方发布,Java虚拟机技术创建人撰写,国内资深Java技术专家翻译。书中基于全新Java SE 8,完整且准确地阐述Java虚拟机规范,是深度了解Java虚拟机和...
同时,书中不仅完整地讲述了由Java SE 8所引入的新特性,例如对包含默认实现代码的接口方法所做的调用,还讲述了为支持类型注解及方法参数注解而对class文件格式所做的扩展,并阐明了class文件中各属性的含义,以及...
《Java虚拟机规范(Java SE 7版)》是Java领域最重要和最权威的著作之一,由Oracle官方发布,基于Java SE 7,对最新的Java虚拟机规范进行了完整且详细的讲解,是深度了解Java虚拟机实现细节的必读之作。由国内几位资深...
同时,书中不仅完整地讲述了由Java SE 8所引入的新特性,例如对包含默认实现代码的接口方法所做的调用,还讲述了为支持类型注解及方法参数注解而对class文件格式所做的扩展,并阐明了class文件中各属性的含义,以及...
《Java虚拟机规范(Java SE 7版)》是Java领域最重要和最权威的著作之一,由Oracle官方发布,基于Java SE 7,对最新的Java虚拟机规范进行了完整且详细的讲解,是深度了解Java虚拟机实现细节的必读之作。由国内几位资深...
它的设计目标是“一次编写,到处运行(Write Once, Run Anywhere)”,这意味着开发者可以使用Java编写应用程序,并在支持Java的任何平台上无需重新编译即可运行,这得益于其独特的跨平台性,通过Java虚拟机(JVM)...
第3章 为JAVA虚拟机编译 ............................................... 53 Java 虚拟机规范 — 目录 第 10 页 / 共 387 页 3.1 示例的格式说明 ................................................. 53 3.2 常量...
JDK(Java SE Development Ki),Java标准开发包,它提供了编译、运行Jlva程序所需的各种工具和资源,包括Java编译Java运行时环境,以及常用的Java类库等 JRE(Java Runtime Environment),Java运行环境,用于运行Jlava...
第3章 为JAVA虚拟机编译 ............................................... 53 Java 虚拟机规范 — 目录 第 10 页 / 共 387 页 3.1 示例的格式说明 ................................................. 53 3.2 常量...
著作:《java jdk 5.0学习笔记》、《java se 6技术手册》、《spring技术手册》等 译作:《ajax实战手册》、《jquery实战手册(第2版)》 个人网站:http://openhome.cc 目录 《java jdk 7学习笔记》 chapter1 ...
SE 11 程序员 I 创建一个简单的 Java 程序 Java 类是使用javac程序编译的。 根据 Java 源文件的内容,编译会生成一个或多个类文件。 一个例子如下所示: javac TestClass . java 使用java程序执行 Java 类。 一个...
Java8的 这是一组脚本,用于从头开始打包...每次调用都会使用所有生成的输出创建一个日志文件。 ./build.sh distclean删除所有内容,包括下载的文件。 ./build.sh clean会删除除已下载文件以外的所有内容。 ./
1JAVA SE 1.1深入JAVA API 1.1.1Lang包 1.1.1.1String类和StringBuffer类 位于java.lang包中,这个包中的类使用时不用导入 String类一旦初始化就不可以改变,而stringbuffer则可以。它用于封装内容可变的字符串。它...
SE 11 程序员 I 创建一个简单的 Java 程序 Java 类是使用javac程序编译的。 根据 Java 源文件的内容,编译会生成一个或多个类文件。 一个例子如下所示: javac TestClass . java 使用java程序执行 Java 类。 一个...
Javah:产生可以调用Java过程的C过程,或建立能被Java程序调用的C过程的头文件。 Javap:Java反汇编器,显示编译类文件中的可访问功能和数据,同时显示字节代码含义。 Jconsole: Java进行系统调试和监控的工具常用...
Java∨ ersion se6 支持脚本语言 引入JDBC40API; 引入 Java Compiler API; 可插拔注解; 增加对 Native PKi( Public Key Infrastructure)、 Java gss( Generic Security Service) Kerberos和 LDAP(Lightweight ...
Java se60发布 3:Java特点 简单地说,Java具有如下特点:简单的、面向对象、平台无关、多线程、分布式、安全、 晑性能、可靠的、解释型、自动垃圾回收等特点。 这里只解释一下平台无关和分布式,其余的在后面会逐步接触...