【基础总结】动态编译

源代码: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,这是错误的,因此:

【基础总结】动态编译_第1张图片
编译失败

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

【基础总结】动态编译_第2张图片
编译成功生成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)进行强制转型,避免这个问题。

你可能感兴趣的:(【基础总结】动态编译)