Java实现运行时编译并动态调用

Java实现运行时编译并动态调用

至于运行时编译有什么优势这里就不赘述了,直接进入主题:
JDK1.6提供了调用javac的接口。我们可以使用这个接口来实现运行时编译java文件,生成.class文件的目的。该类为javax.tools.JavaCompiler类。接下来使用自定义classloader加载,可实现动态调用。

首先,JavaCompiler使用方法如下:

    public static int compile(String name){
        //获得系统的JavaComiler实例(ToolProvider在javax.javax.tools包中)
        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
        //定义一个以char字节的形式输出到控制台的字节流
        OutputStream out = new OutputStream() { 
            @Override
            public void write(int b) throws IOException {
                System.out.print((char)b);
            }
        };
       //run方法第一个参数为java文件绝对路径(相对路径没试过)
       //如果出错了,会将javac的信息输出到第三个参数的输出流
       //如果返回值为0,说明编译成功
       return compiler.run(null, null, out, name);
    }

我们可以将编译好的文件使用classloader动态加载,并调用新编译的类。当然实现调用,必须要有一个公共接口。为了方便起见,我们将带编译放在该工程src/test目录下。工程目录如图所示:
这里写图片描述
其中MyTest工程中的Test文件将会在Complie运行时被Complie编译并加载
Test代码如下:

    package test;

import commonface.DoSomeThing;

public class Test implements DoSomeThing{
    @Override
    public String doSomeThing() {
        return "hello world";
    }

}

双方的公共接口DoSomeThing:

   package commonface;

public interface DoSomeThing {
      public String doSomeThing();
}

最后是编译类Complie:

package complie;
import commonface.DoSomeThing;
import javax.tools.JavaCompiler;
import javax.tools.ToolProvider;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
public class Compile {
    public static int compile(String name){
         //注释见上文
        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
        OutputStream out = new OutputStream() { 
            @Override
            public void write(int b) throws IOException {
                System.out.print((char)b);
            }
        };
       return compiler.run(null, out, out, name);
    }
    public static void run(String classPath) throws Exception{
         //自定义一个ClassLoader,我们需要重载findclass
         ClassLoader loader=new ClassLoader(){
               @Override  
                protected Class<?> findClass(String className)  throws ClassNotFoundException {
                    Class cLass=null;
                    try { 
                        //根据绝对路径找到文件 
                        FileInputStream of=new FileInputStream(new File(className));
                        //一下几步将文件流变成byte数组
                        ByteArrayOutputStream out = new ByteArrayOutputStream(1000);
                        byte[] b = new byte[1000];
                        for (int n;(n = of.read(b)) != -1;) {
                            out.write(b, 0, n);
                       }
                        of.close();
                        byte[] bt=out.toByteArray();
                        //加载类信息
                        cLass= defineClass(bt, 0, bt.length);  
                        out.close();      
                    } catch (Exception e) {  
                        e.printStackTrace(); 
                        throw new ClassNotFoundException();
                    }  
                    return cLass;  
         }};
         //加载类
         Class mc=loader.loadClass(classPath);
         //强制转型,并调用,结果输出在控制台
         DoSomeThing dt=(DoSomeThing)mc.newInstance();
         System.out.println(dt.doSomeThing());
    }
    public static void main(String[] args) throws Exception{
          if(compile(System.getProperty("user.dir")+"\\..\\MyTest\\src\\test\\Test.java")==0){
                System.out.println("Done");
                //javac编译的class文件在java文件同一目录下面
                run(System.getProperty("user.dir")+"\\..\\MyTest\\src\\test\\Test.class");
        } else {
        System.out.println("Fail");
       }
     }
}

文中的Classloader类这里只是简单的提了一下。以后有机会再详细的说吧。另外,改程序在运行成功、如图所示:
这里写图片描述
成功的编译了Test文件,并调用了Test文件重载的doSomeThing函数,将结果输出到控制台中了。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值