1.java通过getSystemJavaCompiler得到的是com.sun.tools.javac.api.JavacTool(应该吧)
2.如果不存在jdk的话(只安装jre),搜寻路径是System.getProperty("java.home")+lib+tools.jar;
3.编译时如果没有指定class生成路径,会在System.getProperty("user.dir")下生成字节码文件,如果需要指定生成路径,可以通过指定编译参数e.g:
String[] path = new String[]{"-d",curPath}; Iterable<String> options = Arrays.asList(path); task = compiler.getTask(out, fileManager, null, options, null, fileObjects);
4.如果需要多次动态编译(一个虚拟机生命周期内),如果仅仅使用class.forname("xxx")会出现每次加载同一个class对象,
因为如果你没有指定类加载器,默认的当前类加载器会先检查是否已经加载过(通过类的全限定名),如果加载过,则直接返回
已经加载过的class对象,不会加载你重新编译过的class,参见如下:
synchronized (getClassLoadingLock(name)) { // First, check if the class has already been loaded Class c = findLoadedClass(name); if (c == null) { long t0 = System.nanoTime(); ........ ........ ........ return c;
所以,如果要每次加载重新编译过的类,两个办法,动态更改类名,采用你自己的类加载器(这里,后来看到有一个urlclassloader类加载器,不知道可行否),自己的类加载器也很简单(重写那两个方法),只需在指定的url中得到类的字节码数组(文件流的读取),参见如下
/* * 重写findclass方法 */ public Class<?> findClass(String name){ byte[] byteCode = loadClassData(name); return defineClass(name,byteCode,0,byteCode.length); } /* * 重写loadclassdata方法 */ public byte[] loadClassData(String name){ //字节码输入流 FileInputStream in = null; //字节码输出流 ByteArrayOutputStream out = null; //返回的字节码数组 byte[] byteCode = null; try{ //创建流 in = new FileInputStream(new File(path+name+".class")); out = new ByteArrayOutputStream(); //开始加载字节码 int c = -1; while((c = in.read())!=-1){ out.write(c); } //转换字节码数组 byteCode = out.toByteArray(); }catch(Exception ex){ ex.printStackTrace(); }finally{ //关闭字节码流 try { in.close(); out.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } return byteCode; }
5.这个是在测试过程中碰到的问题,在服务器的fitnesse等类似当前工作目录不是工程目录的工具或者软件中运行你的类(包含动态编译的代码),如果你指定动态编译类的路径不是绝对路径而是相对路径(比如相对你的工程),会出现找不到指定路径(你动态编译的类)。解决办法有二,如果你的应用不是跨平台或者允许在用户其他目录生成,将动态生成的类路径指定为绝对路径比如c盘根(其他windows上一定有的路径)或者home/${user}下,方法二的情况是你的项目跨平台或者不允许在用户机器或服务器上其他路径上创建文件的话,可以在你的当前运行类的目录下生成动态编译的类文件,参见如下
String curPath = Calculator.class.getResource("/").toString().replace("%20", " ").substring(6);
6.系统的user.dir不可更改,前提是当你启动jvm之后,=。=