zoukankan      html  css  js  c++  java
  • 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类型,否则会将数组中的元素拆分作为该方法的实参。

  • 相关阅读:
    [WPF VTK]三维图形开发基础(一)
    WP开发(一)
    [WPF VTK]三维图形开发基础(四)

    WIN8 下IE突然无法打开(管理员权限可打开)
    [WPF VTK]三维图形开发基础(三)
    堆排序、快排的坑
    双向链表之插入
    [WPF VTK]三维图形开发基础(二)
    [转载]Android界面设计学习日志(一)
  • 原文地址:https://www.cnblogs.com/Scorpicat/p/12150035.html
Copyright © 2011-2022 走看看