认识java的类加载器(二)

来源:互联网 发布:java 日期转换字符串 编辑:程序博客网 时间:2024/04/24 03:26
 

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

原创粉丝点击