79 动态编译与动态运行

动态编译与动态运行

在这样的场景中:我们设计了一个网页,允许用户在网页上输入java代码,提交后获得java代码的执行结果。这个功能,无需用户安装jre或是jdk,就能获得java编译运行的结果。这个功能,就要依赖动态编译与动态运行。

这样设计:用户输入代码,提交后,通过网络流传入到我们的服务器,我们将流接受,转为对应的java文件,然后调用编译器编译它,再调用类加载器或是Runtime执行它对应的class文件,最后我们将执行后的结果,通过流返回给用户,完成功能。

那么这个过程中的:调用编译器与调用类加载器的过程,就是动态编译与动态运行的过程。

如何在程序中动态编译?

我们通过ToolProvider类获取JavaCompiler编译器工具,就可以对指定的文件进行编译。

JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
			int result = compiler.run(null, null, null, "c:/myjava/HelloWorld.java");
			System.out.println(result==0?"编译成功":"编译失败");

  

需要注意的地方:run()方法前三个参数请参考本方法的api。第四个参数传入的时java文件的完整路径。方法返回的结果为0则编译成功,否则为编译失败。

如何在程序中动态运行class文件?

我们有两种方式可以动态加载class文件,它们分别是Runtime类与反射机制运行class文件对应的main方法。

Runtime类

每一个运行的程序都有一个对应的Runtime对象,我们可以通过Runtime.getRuntime()来获取它。通过这个对象,我们可以调用class文件获得一个进程(Process对象),这个进程执行不会显示在当前控制台(如果被加载的class有在控制台输出的语句的话)。但我们可以获得这个进程的标准输出流(一般值System.out,其它情况不知),可以将流导出到文件或是网络。

//动态运行
			Runtime runtime = Runtime.getRuntime();
			Process process = runtime.exec("java -cp c:/myjava HelloWorld");
			InputStream is = process.getInputStream();
			BufferedReader br = new BufferedReader(new InputStreamReader(is));
			String line = "";
			while(null!=(line = br.readLine())) {
				System.out.println(line);
			}

  

需要注意的地方:exec()方法传入的是一个系统指令,这里我们传入的时“java -cp c:/myjava HelloWorld”,注意myjava与HelloWorld之间只有空格没有“/”符号,且类文件不加.class后缀。

标准输入与标准输出流

我不知道是否还存在其它标准输入输出流。

public static final InputStream in “标准”输入流。
public static final PrintStream out “标准”输出流。
InputStream is = System.in;
PrintStream ps = System.out;

反射机制加载class文件

利用反射机制我们可以更灵活的加载class文件,通过一个URL数组我们可以指定一个文件夹,然后使用URLClassLoader类获得类加载器,这个加载器可以加载指定文件夹中的任意一个类。加载的结果是得到这个class文件的Class对象(反射)。然后我们获取这个Class对象的main方法,执行main方法,技能加载这个class文件了。但是加载后似乎并没有对应的输出流...emmm

URL[] urls = new URL[] {new URL("File:/c:/myjava/")};
			URLClassLoader loader = new URLClassLoader(urls);
			Class c = loader.loadClass("HelloWorld");
			Method m = c.getMethod("main", String[].class);
			m.invoke(null, (Object)new String[] {});//这里要注意!

  

注意:在调用invoke()方法时,传入的第一个参数为null,我也不知道为什么。第二个参数为该方法的实参列表,但是这个方法的形参是数组,那么在传入实参时,务必要强转为Object类型,否则会将数组中的元素拆分作为该方法的实参。

posted @ 2020-01-04 18:50  Scorpicat  阅读(273)  评论(0编辑  收藏  举报