2、如何实现自定义的编译器
通常,一个编译器不仅仅要求编译您当前要编译的类,它必须先编译它说依赖的其他类,等其依赖的类加载进来后才能编译当前类,即其必须逐个编译它所依赖的每一个类。而且加载前必须把原代码文件与存在的编译文件的修改时间比较,如果原代码的修改时间后于编译过的文件,那么必须重新编译原文件。
import java.io.*;
//自定义类加载编译器 public class Compilation extends ClassLoader{
//加载类的二进制代码 private byte[] loadClassData(String fileName)throws IOException{
//读取类文件 File file = new File(fileName); if(!file.exists()){ return null; } FileInputStream input = new FileInputStream(file); long length = file.length(); byte[] bt = new byte[(int)length];
int rl = input.read(bt);
if(rl != length){ throw new IOException("不能读取所有内容"); } input.close();
return bt; }
//编译原代码文件 private boolean compile( String javaFile ) throws IOException { // 知会用户在编译的文件 System.out.println( "编译类 : "+javaFile );
// 启动java编译器 Process p = Runtime.getRuntime().exec( "javac "+javaFile );
// 等待编译完成 try { p.waitFor(); } catch( InterruptedException e ) { System.out.println("编译失败"); }
// 返回子进程的出口值,值 0 表示正常终止。 int ret = p.exitValue();
return ret==0; }
public Class loadClass( String name, boolean resolve ) throws ClassNotFoundException {
System.out.println("加载类: "+ name); //目标class对象 Class clas = null; // 查看是否已经加载该类 clas = findLoadedClass( name );
//把类的包结构转化成系统文件目录 String fileStub = name.replace( '.', '/' );
String javaFilename = fileStub+".java"; String classFilename = fileStub+".class"; File javaFile = new File( javaFilename ); File classFile = new File( classFilename );
// 查看是否是最新编译的文件 if (javaFile.exists() && (!classFile.exists() || javaFile.lastModified() > classFile.lastModified())) { try { // 编译文件 if (!compile( javaFilename ) || !classFile.exists()) { throw new ClassNotFoundException( "没找到类文件: "+javaFilename ); } } catch( IOException ie ) { throw new ClassNotFoundException( "找不到类 : " + name); } }
if(classFile.exists()){ //获取字节码 try { byte raw[] = loadClassData(classFilename); // 转化成class对象 clas = defineClass( name, raw, 0, raw.length ); } catch( IOException e){ System.out.println("转化成class对象失败:" + classFilename); } }
// 查找classpath中是否存在 if (clas == null) { clas = findSystemClass(name); } // 是否需要分析字节码 if (resolve && clas != null) resolveClass( clas ); // 找不到该类 if (clas == null) throw new ClassNotFoundException( "类不存在" ); return clas; } } |
public class Pig{ public Pig(){ new PigSon(); } } |
public class PigSon{ public PigSon(){ try{ Class.forName("PigSon2"); }catch(Exception e){ System.out.println(e.getMessage()); } System.out.println("This is PigSon"); } } |
public class PigSon2{ public PigSon2(){ System.out.println("This is PigSon2"); } } |
public class TestCompilation{ public static void main(String[] args){ Compilation cp = new Compilation(); try{ cp.loadClass("Pig",true).newInstance(); }catch(Exception e){ System.out.println(e.getMessage()); } } } |
注意运行时不要编译Pig,PigSon,PigSon2,这样才能够调用自定义的编译器。
加载类: Pig 编译类 : Pig.java 加载类: java.lang.Object 加载类: java.lang.Throwable 加载类: java.lang.Exception 加载类: PigSon 加载类: java.lang.Class 加载类: PigSon2 编译类 : PigSon2.java 加载类: java.lang.System 加载类: java.io.PrintStream This is PigSon This is a pig |