菜鸟学习笔记:Java提升篇12(Java动态性2——动态编译、javassist字节码操作)
Java的动态编译
Java的动态编译是指在Java程序运行时动态的执行编译指令进而执行另一段Java代码,它是在Java6.0中引入的机制。
对于Java动态编译有两种做法,一种是通过Runtime调用Javac,启动新的进程进行操作,比如:
Runtime run = Runtime.getRuntime();
Process process = run.exec("javac HelloWorld.java");
另一种是通过JavaCompiler动态编译,
public static void main(String[] args) throws IOException {
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
int result = compiler.run(null, null, null, "D:\\HelloWorld.java");
//这里四个参数中:
//第一个参数为一个流对象,表示为java编译器提供的参数,如果为null表示System.in
//第二个参数表示得到Java编译器的输出信息
//第三个编译器代表接收编译器的错误消息
//第四个参数为一个字符串或字符串数组,表示传入的Java源文件
//返回值是一个int类型的值,0代表编译成功,非0代表编译失败
//执行完成后会生成class文件
System.out.println(result == 0 ? "编译成功" : "编译失败");
//执行java 命令 , 空参数, 所在文件夹
Process process = Runtime.getRuntime().exec("java HelloWorld");
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String str;
while ((str = bufferedReader.readLine()) != null) {
System.out.println(str);
}
}
执行后生成的文件:
我们也可以通过反射来运行编译好的类:
public static void main(String[] args) throws IOException {
try {
URL[] urls = new URL[] {
new URL("file:/" + "D:/HelloWorld") };
//加载class文件
URLClassLoader loader = new URLClassLoader(urls);
// 通过反射调用此类
Class clazz = loader.loadClass("HelloWorld");
Method m = clazz.getMethod("main", String[].class);
// 由于可变参数是jdk5.0之后才有,上面代码会编译成m.invoke(null,"aa","bb");会发生参数不匹配的问题
// 因此必须加上Object 强转
m.invoke(null, (Object) new String[] {
});
} catch (Exception e) {
e.printStackTrace();
}
}
执行结果与上例相同。
通过脚本引擎执行代码
Java脚本引擎是JDK6.0之后添加的新功能,它使得Java可以通过一套固定的接口与各种脚本引擎交互,从而达到在Java平台上调用各种脚本语言的目的,是Java联通其他脚本语言的桥梁,使得Java可以把一些复杂业务交给脚本语言处理,大大提高了开发效率 。
以Javascript为例,Java脚本API可以获取脚本程序的输入,通过脚本引擎运行脚本返回运行结果。Java调用JS运用的是Rhino,它是Java编写的Javascript开源实现。通过脚本引擎的运行上下文可以在脚本和Java平台之间交换数据。调用方式如下:
ScriptEngineManager sem = new ScriptEngineManager();
ScriptEngine engine = sem.getEngineByName("javascript");
运用engine对象就可以实现Java与