java之动态编译

一,通过JavaCompiler动态编译

public static void main(String[] args) {
        String str = "public class Demo01 {public static void main(String[] args){System.out.println(\"HaHa,heihei!\");}}";
        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
        int result = compiler.run(null, null, null, "D:/java/Demo01.java");
        System.out.println(result);
    }

步骤:
①写要编译的内容
②通过ToolProvider的一个方法getSystemJavaCompiler()获取JavaCompiler对象
③调用JavaCompiler.run();
这个函数有四个参数:
第一个参数:为java编译器提供参数
第二个参数:得到java编译器的输出信息
第三个参数:接收编译器的错误信息
第四个参数:可变参数(是一个String数组)能传入一个或多个Java源文件
返回值:0扁食编译成功,非0表示编译失败

PS:在执行的时候可能会出现异常如下:

Exception in thread "main" java.lang.NullPointerException
    at com.vvvvvv.TestCompiler.Demo01.main(Demo01.java:11)

这是由于第②步执行的时候,返回的是Null。因此在调用compiler.run的时候抛出了空指针异常。
为啥会这样呢?查看了下ToolProvider的源代码,发现如下这么一段….

 private Class<?> findSystemToolClass(String toolClassName)
        throws MalformedURLException, ClassNotFoundException
    {
        // try loading class directly, in case tool is on the bootclasspath
        try {
            return Class.forName(toolClassName, false, null);
        } catch (ClassNotFoundException e) {
            trace(FINE, e);

            // if tool not on bootclasspath, look in default tools location (tools.jar)
            ClassLoader cl = (refToolClassLoader == null ? null : refToolClassLoader.get());
            if (cl == null) {
                File file = new File(System.getProperty("java.home"));
                if (file.getName().equalsIgnoreCase("jre"))
                    file = file.getParentFile();
                for (String name : defaultToolsLocation)
                    file = new File(file, name);

                // if tools not found, no point in trying a URLClassLoader
                // so rethrow the original exception.
                if (!file.exists())
                    throw e;

                URL[] urls = { file.toURI().toURL() };
                trace(FINE, urls[0].toString());

                cl = URLClassLoader.newInstance(urls);
                refToolClassLoader = new WeakReference<ClassLoader>(cl);
            }

            return Class.forName(toolClassName, false, cl);
        }
    }

我已经设置了JAVA_HOME环境变量,指向了我的JRE安装目录C:\Java\jre6, 注意查找文件的代码…

for (String name : defaultToolsLocation)
file = new File(file, name);
也就是说会查找目录C:\Java\jre6\lib\tools.jar

但是注意的是tools.jar并不在jre中,而是在jdk安装目录下,因此我手动把这个jar文件从jdk目录下拷贝到了jre目录下,再次运行上面的代码就没有问题了!同时注意到在代码工程目录下生成了一个名为Main.class的文件,这个确实说明了动态类Main已经编译成功了!

利用IO流将str读到文件中进行编译
较不规范。

public static void main(String[] args) throws Exception {
        String str = "public class Demo01 {public static void main(String[] args){System.out.println(\"HaHa,heihei!\");}}";
        String dest = "D:/java/Demo01.java";
        File f = new File(dest);
        OutputStream os = null;
        os = new FileOutputStream(f,true);
        byte[] bytes = str.getBytes();
        os.write(bytes, 0, bytes.length);
        os.flush();
        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
        int result = compiler.run(null, null, null,dest);
        System.out.println(result==0?"编译成功":"编译失败");
        os.close();
    }

二,通过Runtime.getRuntime()运行编译好的类

步骤:
①通过run.exec(String str)运行,返回一个Process对象
②通过process.getInputStream()返回一个输入流
③将字节流转化为字符流
④读取出运行结果

//进行动态编译
Runtime run = Runtime.getRuntime();
Process process= run.exec("java -cp d:/java Demo01");

InputStream in = process.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
        String info = "";
        while((info = reader.readLine()) != null){
            System.out.println(info);
        }

三,通过反射运行编译好的类

步骤:
①将路径存入URL[]中。
②用类加载器加载我们要运行的类
③获取加载的类
④获取要调用的方法
⑤执行方法

URL[] urls = new URL[] {new URL("file:/"+"d:/java/")};
URLClassLoader classLoader = new URLClassLoader(urls);
Class c = classLoader.loadClass("Demo01");
Method m = c.getMethod("main", String[].class);
m.invoke(null, (Object)new String[]{});

注意:
m.invoke(null, (Object)new String[]{});中必须加上Object转型。
由于可变参数是JDK5.0之后才有。
m.invoke(null, (Object)new String[]{});会编译成:m.invoke(null,”aa”,”bb”),就发生了参数个数不匹配的问题。
因此,必须要加上(Object)转型,避免这个问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值