Java_Java SE6调用动态编译
转自:http://www.cnblogs.com/flyoung2008/archive/2011/11/14/2249017.html
一、使用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_Java SE6调用动态编译的更多相关文章
- python3.6调用c语言动态编译文件 c语言编译可执行文件和动态编译等
1.c的代码 dfunc.c #include<stdio.h> int dgfunc(int n) { ){ ; }else{ )+dgfunc(n-); } } 2.动态编译 cmd ...
- Java学习:注解,反射,动态编译
狂神声明 : 文章均为自己的学习笔记 , 转载一定注明出处 ; 编辑不易 , 防君子不防小人~共勉 ! Java学习:注解,反射,动态编译 Annotation 注解 什么是注解 ? Annotat ...
- 使用PyQt(Python+Qt)+动态编译36行代码实现的计算器
PyQt是基于跨平台的图形界面C++开发工具Qt加Python包装的一个GPL软件(GPL是GNU General Public License的缩写,是GNU通用公共授权非正式的中文翻译),Qt基于 ...
- Java_java动态编译整个项目,解决jar包找不到问题
java动态编译整个项目,解决jar包找不到问题原文:http://itzyx.com/index.php/javac/ 动态将java文件编译为class文件解决方案:将temp\sdl\src目录 ...
- C++---初识《通过g++ / makefile 编译和调用动态库so文件》(ubuntu)
C++---初识<通过g++ / makefile 编译和调用动态库so文件>(ubuntu) ------------------------目录------------------- ...
- __del__ PyPy和CPython的不同点 动态编译(注意不是解释) 析构函数被调用的次数
小结 1.cpy的垃圾回收会对调用__del__多次:pypy仅仅一次: https://www.liaoxuefeng.com/wiki/1016959663602400/1016966024263 ...
- java动态编译笔记
1 前言 Java的动态编译知识,真真在实际开发中并不是经常遇到.但是学习java动态编译有助于我们从更深一层次去了解java.对掌握jdk的动态代理模式,这样我们在学习其他一些开源框架的时候就能够知 ...
- (转载)JAVA动态编译--字节代码的操纵
在一般的Java应用开发过程中,开发人员使用Java的方式比较简单.打开惯用的IDE,编写Java源代码,再利用IDE提供的功能直接运行Java 程序就可以了.这种开发模式背后的过程是:开发人员编写的 ...
- ZKWeb网站框架的动态编译的实现原理
ZKWeb网站框架是一个自主开发的网页框架,实现了动态插件和自动编译功能. ZKWeb把一个文件夹当成是一个插件,无需使用csproj或xproj等形式的项目文件管理,并且支持修改插件代码后自动重新编 ...
随机推荐
- AngularJS讲义-控制器
在Angular中,控制器(Controller)就是基于JavaScript的构造方法,主要用来构造模型并建立模型和视图之间的数据绑定.控制器里面定义了应用程序的逻辑和行为. 通过ng-contro ...
- 算法系列:CSAPP 推荐
转载自:https://book.douban.com/review/6093947/ 如果你觉得这本书过于厚重担心看不下来的话,不妨跟着coursera的Hardware/Software Inte ...
- C与C++之间相互调用
1.导出C函数以用于C或C++的项目 如果使用C语言编写的DLL,希望从中导出函数给C或C++的模块访问,则应使用 __cplusplus 预处理器宏确定正在编译的语言.如果是从C++语言模块使用,则 ...
- c/s模式 (C#)下Ftp的多文件上传及其上传进度
因为项目要求,制作的一个多文件上传,并显示进度条一段代码(vs2005环境).(只为粗略的实现,代码并不规范) 当多个文件上传的时候,需要依次队列形式一个个上传,当上传某个文件的时候,锁定进程,上传完 ...
- 攻城狮在路上(叁)Linux(二十五)--- linux内存交换空间(swap)的构建
swap的功能是应付物理内存不足的状况,用硬盘来暂时放置内存中的信息. 对于一般主机,物理内存都差不多够用,所以也就不会用到swap,但是对于服务器而言,当遇到大量网络请求时或许就会用到. 当swap ...
- TortoiseSVN常用操作说明
TortoiseSVN是windows下其中一个非常优秀的SVN客户端工具.通过使用它,我们可以可视化的管理我们的版本库.不过由于它只是一个客户端,所以它不能对版本库进行权限管理. TortoiseS ...
- poj 2337 欧拉回路输出最小字典序路径 ***
把26个小写字母当成点,每个单词就是一条边. 然后就是求欧拉路径. #include<cstdio> #include<iostream> #include<algori ...
- 跟着鸟哥学Linux系列笔记0-扫盲之概念
相关缩写全称: POSIX(Portable Operation System Interface):可携式操作系统接口,重点在于规范内核与应用之间的接口,由IEEE定义发布 IEEE: 美国电气与电 ...
- Android:dimen尺寸资源文件的使用(转)
为了适配不同的分辨率. dimen.xml在values文件夹下面 <resources> <!-- Default screen margins, per the Android ...
- 关于如何在MFC工程中输入不同的数据进行调试
我们可以采用c++的文件输入输出来进行调试 这样就绕过了不能使用黑窗口输入数据就不能调试的思维定式 不是黑窗口的我们都可以考虑用文件流输入输出 或者用控件来输入? http://blog.csdn.n ...