`
bat0906
  • 浏览: 27696 次
  • 性别: Icon_minigender_1
  • 来自: 第九天堂
社区版块
存档分类
最新评论

Java SE6调用动态编译

    博客分类:
  • java
 
阅读更多

一、使用JavaCompiler接口编译java源程序

  我们可以通过ToolProvider类的静态方法getSystemJavaCompiler来得到一个JavaCompiler接口的实例。

 JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();

  JavaCompiler中最核心的方法是run。通过这个方法可以编译java源程序。这个方法有3个固定参数和1个可变参数(可变参数是从Jave SE5开始提供的一个新的参数类型,用type… argu表示)。前3个参数分别用来为java编译器提供参数、得到Java编译器的输出信息以及接收编译器的错误信息,后面的可变参数可以传入一个或多 个Java源程序文件。如果run编译成功,返回0。

 int run(InputStream in, OutputStream out, OutputStream err, String... arguments) 

  如果前3个参数传入的是null,那么run方法将以标准的输入、输出代替,即System.in、System.out和System.err。

  下面是利用java动态编译实现eval功能:

复制代码
package com.flyoung;

import java.io.File;
import java.io.FileWriter;
import java.io.PrintWriter;
import java.lang.reflect.Method;

import javax.tools.JavaCompiler;
import javax.tools.ToolProvider;

public class JavacTest {
    public JavacTest(){
        
    }
    
    public static void eval(String str){
        System.out.println(System.getProperty("user.dir"));//当前工作目录
        String s = "public class Temp{" ;
        s+="\r\n"+"      public static String call(String ss){      ";        
        s+="\r\n"+"            System.out.println(\""+str+"\");  ";
        s+="\r\n"+"            return \"return_str\"; ";
        s+="\r\n"+"      }";
        s+="\r\n"+"}";
        try{
            File file = new File("Temp.java");
            PrintWriter pw = new PrintWriter(new FileWriter(file));
            //pw.println(s);
            //pw.write(s);
            pw.close();
            
            //动态编译
            JavaCompiler javac = ToolProvider.getSystemJavaCompiler();
            int status = javac.run(null, null, null, "-d",System.getProperty("user.dir")+"/bin","Temp.java");
            if(status!=0){
                System.out.println("没有编译成功!");
            }
            
            //动态执行
        Class cls = Class.forName("Temp");//返回与带有给定字符串名的类 或接口相关联的 Class 对象。
        Method method = cls.getDeclaredMethod("call", String.class);//返回一个 Method 对象,该对象反映此 Class 对象所表示的类或接口的指定已声明方法
        String result= (String)method.invoke(null, str);//静态方法第一个参数可为null,第二个参数为实际传参
        System.out.println(result);
        }catch(Exception e){
            e.printStackTrace();
        }
    
    }
    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        JavacTest javacTest = new JavacTest();
        javacTest.eval("input_str");

    }

}
复制代码

二、使用StandardJavaFileManager编译java源程序

  在Java SE6中最好的方法是使用StandardJavaFileManager类。这个类可以很好地控制输入、输出,并且可以通过DiagnosticListener得到诊断信息,而DiagnosticCollector类就是listener的实现。
  使用StandardJavaFileManager需要两步。首先建立一个DiagnosticCollector实例以及通过 JavaCompiler的getStandardFileManager()方法得到一个StandardFileManager对象。最后通过 CompilationTask中的call方法编译源程序。

详细请看:http://doc.java.sun.com/DocWeb/api/javax.tools.JavaCompiler

示例:

复制代码
package com.flyoung;
import java.io.File; 
import java.io.FileWriter; 
import java.util.Arrays; 
import javax.tools.JavaCompiler; 
import javax.tools.StandardJavaFileManager; 
import javax.tools.ToolProvider; 
import javax.tools.JavaCompiler.CompilationTask; 
public class DynamicCompileTest { 
  public static void main(String[] args) throws Exception { 
      //1.创建需要动态编译的代码字符串 
      String nr="\r\n";//回车换行 
      String source="package com.flyoung.hello;"+nr+ 
      "    public class Hello{"+nr+ 
      "     public static void main(String[] args){"+nr+ 
      "     System.out.println(\"helloworld!\");"+nr+ 
      "}"+nr+ 
      "}"  ; 
     //2.将预动态编译的代码写入文件中1:创建临时目录 2:写入临时文件 
      File dir=new File(System.getProperty("user.dir")+"/temp");//临时目录 
     //如果/temp目录不存在创建temp目录 
     if(!dir.exists()){
        dir.mkdir(); 
} 
     FileWriter writer=new FileWriter(new File(dir,"Hello.java")); 
     writer.write(source);//将字符串写入文件中 
     writer.flush(); 
     writer.close(); 
     //3:取得当前系统java编译器 
     JavaCompiler javaCompiler=ToolProvider.getSystemJavaCompiler(); 
   //4:获取一个文件管理器StandardJavaFileManage 
     StandardJavaFileManager javaFileManager=javaCompiler.getStandardFileManager(null, null, null); 
   //5.文件管理器根与文件连接起来 
     Iterable it=javaFileManager.getJavaFileObjects(new File(dir,"Hello.java")); 
   //6.创建编译的任务 
    CompilationTask task=javaCompiler.getTask(null, 
    javaFileManager,null,Arrays.asList("-d","./temp"), null, it); 
   //执行编译 
    task.call(); 
    javaFileManager.close(); 
  } 
}
复制代码

三、从内存中动态编译源程序

      JavaCompiler 不仅能编译硬盘上的 Java 文件,而且还能编译内存中的 Java 代码,然后使用reflection来运行他们。

复制代码
package com.flyoung;
import java.io.IOException; 
import java.net.URI; 
import javax.tools.SimpleJavaFileObject; 
public class JavaStringObject extends SimpleJavaFileObject { 
  private String code; 
  public JavaStringObject(String name, String code) { 
   //super(URI.create("string:///" + name.replace('.', '/') + Kind.SOURCE.extension), Kind.SOURCE); 
   super(URI.create(name+".java"), Kind.SOURCE); 
   this.code = code; 
  } 
  @Override 
  public  CharSequence  getCharContent(boolean  ignoreEncodingErrors)  throws  IOException 
  { 
   return code; 
  } 
} 
复制代码

 

复制代码
package com.flyoung;

import java.io.PrintWriter; 
import java.io.StringWriter; 
import java.lang.reflect.Method; 
import java.net.URL; 
import java.net.URLClassLoader; 
import java.util.Arrays; 
import javax.tools.JavaCompiler; 
import javax.tools.JavaFileObject; 
import javax.tools.ToolProvider; 
import javax.tools.JavaCompiler.CompilationTask; 
public class DynamicCompileTest { 
  public static void main(String[] args) throws Exception { 
   /* 
     * 编译内存中的java代码 
     */ 
   // 将代码写入内存中 
    StringWriter writer = new StringWriter();// 内存字符串输出流 
    PrintWriter out = new PrintWriter(writer); 
    out.println("package com.flyoung.hello;"); 
    out.println("public class Hello{"); 
    out.println("public static void main(String[] args){"); 
    out.println("System.out.println(\"helloworld!\");"); 
    out.println("}"); 
    out.println("}"); 
    out.flush(); 
    out.close(); 
   // 开始编译 
    JavaCompiler javaCompiler = ToolProvider.getSystemJavaCompiler(); 
    JavaFileObject fileObject = new JavaStringObject("Hello", writer.toString());
    CompilationTask  task=javaCompiler.getTask(null, null, null, 
    Arrays.asList("-d","./bin"), null, Arrays.asList(fileObject)); 
    boolean success=task.call(); 
       if(!success){ 
         System.out.println("编译失败!"); 
       } 
       else{ 
         System.out.println("编译成功!"); 
        //利用反射调用其中的main()方法 
        // Class class1=Class.forName("com.flyoung.hello.Hello"); 
        //ClassLoader是自动去从当前工作目录下的classpath路径下去找 也就是bin目录下 
 //Class class1=ClassLoader.getSystemClassLoader().loadClass("com.flyoung.hello.Hello"); 
                
//利用URLClassLoader去实例化一个Class类  类文件可以放在任意位置,这样就很方便了 
         URL[] urls=new URL[]{new URL("file:/"+"./bin/")}; 
         URLClassLoader classLoader=new URLClassLoader(urls); 
         Class class1=classLoader.loadClass("com.flyoung.hello.Hello"); 
         Method method=class1.getDeclaredMethod("main",String[].class); 
         String[] args1={null}; 
         method.invoke(class1.newInstance(),args1);  
       } 
  } 
} 
复制代码
 
 
分享到:
评论

相关推荐

    Java6动态编译案例

    Java6动态编译案例主要涉及的是Java平台中的Java编译器API(Java Compiler API),这是Java SE 6引入的一个重要特性,允许程序在运行时动态地编译源代码。这个功能使得开发者能够在运行的应用程序中生成和编译Java类...

    java SE6从入门到精通源代码

    Java SE6,全称为Java Standard Edition 6,是Oracle公司发布的一个重要的Java开发平台版本,主要面向桌面应用和服务器端应用程序开发。这个平台包含了Java运行环境(JRE)和Java开发工具集(JDK),提供了丰富的API...

    Java虚拟机规范.Java SE 8版.zip

    同时,书中不仅完整地讲述了由Java SE 8所引入的新特性,例如对包含默认实现代码的接口方法所做的调用,还讲述了为支持类型注解及方法参数注解而对class文件格式所做的扩展,并阐明了class文件中各属性的含义,以及...

    Web环境下Java表达式的动态编译与计算.pdf

    本文介绍了一种在Web环境下实现Java表达式的动态编译与计算的方法,该方法利用Java SE 6提供的编译器API实现动态编译,自定义类装载器装入字节代码,并使用反射机制调用计算方法,实现了Java表达式的动态编译与计算...

    java虚拟机规范 Java SE7

    1. **类文件结构**:Java源代码被编译成字节码,存储在类文件中。每个类文件包含元数据、方法和字段定义。了解类文件格式有助于理解JVM如何加载和执行字节码。 2. **字节码指令集**:JVM使用一套简单的指令集来执行...

    Java虚拟机规范(Java SE 7).pdf

    《Java虚拟机规范(Java SE 7)》是Java开发者深入理解Java运行机制的重要参考资料,它详细阐述了Java虚拟机(JVM)的工作原理和内存管理机制,为开发者提供了宝贵的洞察力,帮助他们优化程序性能,理解和解决运行时...

    Java SE 6: Top 10 Features

    Java SE 6允许开发者直接访问编译器,这意味着可以在运行时动态编译代码,这对于提高性能和灵活性非常有帮助。 #### 7. 可插拔注解 可插拔注解是Java SE 6引入的一项新特性,它允许开发者定义自定义注解处理器来...

    Java虚拟机规范(Java SE 7)

    3. invokedynamic指令:这是Java 7引入的一个新字节码指令,用于动态语言支持,允许在运行时动态绑定方法调用,提高了脚本语言的性能。 4. 并发与多线程:Java SE 7提供了新的并发工具,如Fork/Join框架,用于解决...

    java SE最经典的桌面小程序(N多demo)适合初学者

    9. **反射与注解**:反射机制让程序在运行时可以动态访问类、接口和对象的信息,而注解则提供了一种元数据,可以在编译期或运行期对代码进行处理。DEMO将展示如何使用反射和注解来增强程序的灵活性和可维护性。 10....

    java se全程学习案例

    Java SE(Java Standard Edition)是Java编程语言的核心版本,它为开发桌面应用程序、服务器端应用程序提供了基础框架。这个“java se全程学习案例”压缩包包含了作者在深入学习Java SE过程中的实战代码,对于初学者...

    groovy调用java-se类库学习案例 Java学习资料

    由于Groovy被编译为Java字节码,所以它可以无缝地使用任何Java类库,包括Java SE中的标准API。在Groovy代码中,你可以像在Java中一样导入Java的包,例如`import java.util.*`,这样就可以使用Java集合框架、I/O流、...

    java调用vc的dll

    Java调用VC编写的DLL(动态链接库)是跨平台编程中的常见需求,尤其是在需要利用C++或VC++实现的高性能计算或者系统级功能时。本文将深入探讨如何在Java中调用VC编译的DLL,并提供相关知识点的详细解释。 1. **JNI...

    java2se6 (chm)帮助文档

    Java 2 Standard Edition 6(Java SE 6)是Java平台的一个重要版本,它提供了广泛的功能和改进,为开发者提供了更高效、更易用的编程环境。本篇将围绕Java SE 6的帮助文档进行深入探讨,揭示其中的核心知识点。 1. ...

    Java虚拟机规范(Java SE 7)1

    《Java虚拟机规范(Java SE 7版)》是Java开发者深入理解JVM内部机制的重要参考资料。该规范定义了Java虚拟机的行为,确保所有Java实现的兼容性。以下是其中一些关键知识点的详细说明: 1. **Java虚拟机的架构**:...

    Oracle公司 Java8 Java SE 8 Programmer I 认证考试1z0-808题库 总167题

    ### Oracle公司 Java8 Java SE 8 Programmer I 认证考试1z0-808题库解析 #### 考试概述 Oracle公司的Java SE 8 Programmer I认证考试(代码:1z0-808)是针对Java开发者的专业认证之一。该考试主要考察考生对Java ...

    The Java® Virtual Machine Specification Java SE 12 Edition.rar

    《Java® Virtual Machine Specification Java SE 12 Edition》是官方发布的关于JVM在Java SE 12版本中的详细规范,旨在定义JVM如何执行字节码、管理内存以及实现各种平台无关的特性。 1. **JVM概述**: - JVM是...

    The Java Language Specification, Java SE 12 Edition.rar

    《Java语言规范,Java SE 12版》是Java开发者不可或缺的重要参考资料,它详细定义了Java 12的语法、语义以及编程模型。这份规范是理解Java平台核心特性的基石,涵盖了从基本数据类型、控制流程到类、接口、异常处理...

    最新 java se8 虚拟机 详解

    6. **新的数值类型**:Java 8引入了`java.lang.Integer`和`java.lang.Long`的新的静态方法,如`sum()`、`min()`和`max()`,以及`Optional`类,用于更好地处理null值,减少空指针异常。 7. **改进的垃圾收集器**:...

    Java Virtual Machine Specification Java SE 7 中文版

    6. 多线程:Java SE 7的JVM提供了多线程支持,允许程序同时执行多个任务。线程通过调用start()方法启动,共享同一块内存空间,通过同步机制如synchronized关键字和wait/notify机制来避免数据竞争。 7. 反射:Java...

Global site tag (gtag.js) - Google Analytics