美文网首页
【Java基础】动态编译

【Java基础】动态编译

作者: 灰色孤星 | 来源:发表于2018-10-22 11:04 被阅读0次

    源代码:https://gitee.com/AgentXiao/reflection
    动态编译要点:
    1、使用场景(在线代码测评)
    2、动态编译的两种方式
    3、动态运行编译好的文件的两种方式

    一、使用场景

    在程序运行过程中,需要再次编译其他的程序。比如在线测评系统,要求在线对java文件进行编译和运行。

    二、实现动态编译

    动态编译的实现有两种做法:
    1、通过Runtime调用javac,启动新的进程去操作。

    Runtime run = Runtime.getRuntime();
    Process process = run.exec("javac d:/test/test.java"); 
    

    2、通过JavaCompiler动态编译。

    /**
     * @ClassName Demo01
     * @Description 测试动态编译
     * @Author xwd
     * @Date 2018/10/21 21:42
     */
    public class Demo01 {
        public static void main(String[] args) {
            JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
            int result = compiler.run(null,null,null,"D:/test/a.java");
            System.out.println(result == 0 ? "编译成功" : "编译失败");
        }
    }
    

    由于文件名为a.java,但是定义了public class test,这是错误的,因此:

    编译失败

    将文件名修改为test.java后编译成功,生成了class文件。

    编译成功生成class文件

    三、动态运行编译好的类

    1、通过Runtime.getRuntime()运行启动新的进程运行

    /**
     * @ClassName Demo03
     * @Description 动态运行编译好的类
     * @Author xwd
     * @Date 2018/10/22 10:44
     */
    public class Demo03 {
        public static void main(String[] args) throws IOException {
            Runtime run = Runtime.getRuntime();
            //run.exec("javac d:/test/test.java");
            Process process = run.exec("java -cp d:/test/ test");
    
            BufferedReader br = new BufferedReader(new InputStreamReader(process.getInputStream()));
            String info = "";
            while((info = br.readLine()) != null){
                System.out.println(info);
            }
    
        }
    }
    

    2、通过反射运行编译好的类

    /**
     * @ClassName Demo04
     * @Description 通过反射运行编译好的类
     * @Author xwd
     * @Date 2018/10/22 10:52
     */
    public class Demo04 {
        public static void main(String[] args) throws Exception {
            runJavaClassByReflect("D:/test/","test");
        }
    
        public static void runJavaClassByReflect(String dir,String classFile) throws Exception{
            try {
                //通过url获得Class类对象
                URL[] urls = new URL[] {new URL("file:/"+dir)};
                URLClassLoader loader = new URLClassLoader(urls);
                Class c = loader.loadClass(classFile);
                //调用加载类的main方法(必须使用Object转型)
                c.getMethod("main",String[].class).invoke(null,(Object)new String[]{});
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    

    这里需要注意的是:
    由于可变参数是JDK1.5之后才有的,因此在

    c.getMethod("main",String[].class).invoke(null,(Object)new String[]{"aa","bb"});
    

    中,如果不加(Object)进行强制转型的话,编译器会编译成:

    .invoke(null,"aa","bb");
    

    但是main方法的参数是字符串数组,会发生不匹配问题。

    错误参数个数异常

    因此必须使用(Object)进行强制转型,避免这个问题。

    相关文章

      网友评论

          本文标题:【Java基础】动态编译

          本文链接:https://www.haomeiwen.com/subject/ldpizftx.html