学习动态编译的使用
注:执行动态编译时如果一直报 类未找到的错,但实际上类存在的时候,可以把jdk目录里面lib目录下的tools.jar包复制一份到jre目录里面的lib目录下。
一、动态编译的应用场景
浏览器端编写java代码,上传服务器编译和运行
服务器动态加载某些类文件进行编译之类的
二、动态编译的两种做法
1. 通过Runtime调用javac,启动新的进程去执行
Runtime run=Runtime.getRuntime();
Process process = run.exec(“javac -cp f:/MyJava HelloWorld”);//-cp 指的是 classpath
2. 通过JavaCompiler动态编译
三、动态编译怎么用
事先在F盘下的MyJava目录中准备好了一个HelloWorld.java,代码如下:
public class HelloWorld{
public static void main(String [] args){
System.out.println("上午好~");
}
}
1. 动态编译java源文件
package com.xyj.dynamiccompiler;
import java.io.BufferedWriter;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import javax.tools.JavaCompiler;
import javax.tools.ToolProvider;
/**
* 动态编译源文件
*/
@SuppressWarnings("all")
public class Demo01 {
public static void main(String[] args) throws Exception {
//获取Java编译器
JavaCompiler compiler=ToolProvider.getSystemJavaCompiler();
//调用run方法,进行动态编译
int result = compiler.run(null, null, null,"f:/MyJava/HelloWorld.java");
//result返回结果为0表示编译成功 非0表示编译失败
System.out.println(result==0?"编译成功":"编译失败");
//编译成功后,我们发现在f:/MyJava目录下多了一个HelloWorld.class
//动态编译字符串 (先写出为临时文件 再动态编译)
String str="public class Hi{public static void main(String[]args) {System.out.println(\"Hi!!!\");}}";
BufferedWriter writer=new BufferedWriter(new OutputStreamWriter(new FileOutputStream("f:/MyJava/Hi.java")));
writer.write(str);
writer.flush();
JavaCompiler compiler2=ToolProvider.getSystemJavaCompiler();
int result2 = compiler2.run(null, null, null,"f:/MyJava/Hi.java");
System.out.println(result2==0?"编译成功":"编译失败");
writer.close();
}
}
控制台分别输出两行“编译成功”
2. 动态运行编译好的java文件
package com.xyj.dynamiccompiler;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
/**
* 动态运行编译好的类
*/
@SuppressWarnings("all")
public class Demo02 {
public static void main(String[] args) throws Exception {
//方式一:通过 Runtime.getRuntime()运行启动新的进程运行
Runtime run=Runtime.getRuntime();
Process process = run.exec("java -cp f:/MyJava HelloWorld");//-cp 指的是 classpath
InputStream is = process.getInputStream();
BufferedReader reader=new BufferedReader(new InputStreamReader(is,"utf-8"));
String line=null;
while((line=reader.readLine())!=null) {
System.out.println(line);
}
//方式二:通过反射运行编译好的类
URL[] urls=new URL[] {new URL("file:/"+"f:/MyJava/")};
URLClassLoader loader=new URLClassLoader(urls);
Class<?> c = loader.loadClass("HelloWorld");
//调用加载类的main方法
Method method = c.getMethod("main",String[].class);
method.invoke(null,(Object)new String[] {});//因为main是静态方法,所以不需要传实例
//为什么上面的String类型的数组要转为Object类型,假如我们传的有参数,不强转Object的话,会被编译成可变参数,参数与main方法参数不匹配则会报错
}
}
控制台分别输出两行“上午好~”