知识大全 Java SE6调用Java编译器的两种新方法

Posted

篇首语:时间是把锋利的刀,成全过我的疯狂,也粉碎过我的梦想。本文由小常识网(cha138.com)小编为大家整理,主要介绍了知识大全 Java SE6调用Java编译器的两种新方法相关的知识,希望对你有一定的参考价值。

Java SE6调用Java编译器的两种新方法  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!

      在很多Java应用中需要在程序中调用Java编译器来编译和运行 但在早期的版本中(Java SE 及以前版本)中只能通过tools jar中的 sun tools javac包来调用Java编译器 但由于tools jar不是标准的Java库 在使用时必须要设置这个jar的路径 而在Java SE 中为我们提供了标准的包来操作Java编译器 这就是javax tools包 使用这个包 我们可以不用将jar文件路径添加到classpath中了    一 使用JavaCompiler接口来编译Java源程序   使用Java API来编译Java源程序有很多方法 现在让我们来看一种最简单的方法 通过JavaCompiler进行编译    我们可以通过ToolProvider类的静态方法getSystemJavaCompiler来得到一个JavaCompiler接口的实例 JavaCompiler piler = ToolProvider getSystemJavaCompiler();   JavaCompiler中最核心的方法是run 通过这个方法可以编译java源程序 这个方法有 个固定参数和 个可变参数(可变参数是从Jave SE 开始提供的一个新的参数类型 用type… argu表示) 前 个参数分别用来为java编译器提供参数 得到Java编译器的输出信息以及接收编译器的错误信息 后面的可变参数可以传入一个或多个Java源程序文件 如果run编译成功 返回 int run(InputStream in OutputStream out OutputStream err String arguments)   如果前 个参数传入的是null 那么run方法将以标准的输入 输出代替 即System in System out和System err 如果我们要编译一个test java文件 并将使用标准输入输出 run的使用方法如下 int results = tool run(null null null test java );   下面是使用JavaCompiler的完整代码 import java io *;import javax tools *;public class test_pilerapi  public static void main(String args[]) throws IOException     JavaCompiler piler = ToolProvider getSystemJavaCompiler();   int results = piler run(null null null test java );   System out println((results == )? 编译成功 : 编译失败 );   // 在程序中运行test   Runtime run = Runtime getRuntime();   Process p = run exec( java test );   BufferedInputStream in = new BufferedInputStream(p getInputStream());   BufferedReader br = new BufferedReader(new InputStreamReader(in));   String s;   while ((s = br readLine()) != null)    System out println(s);  public class test  public static void main(String[] args) throws Exception     System out println( JavaCompiler测试成功! );     编译成功的输出结果    编译成功   JavaCompiler测试成功   编译失败的输出结果 test java: : 找不到符号符号 方法 printlnln(java lang String)位置 类 java io PrintStreamSystem out printlnln( JavaCompiler测试成功! );^ 错误编译失败

  二 使用StandardJavaFileManager编译Java源程序   在第一部分我们讨论调用java编译器的最容易的方法 这种方法可以很好地工作 但它确不能更有效地得到我们所需要的信息 如标准的输入 输出信息 而在Java SE 中最好的方法是使用StandardJavaFileManager类 这个类可以很好地控制输入 输出 并且可以通过DiagnosticListener得到诊断信息 而DiagnosticCollector类就是listener的实现    使用StandardJavaFileManager需要两步 首先建立一个DiagnosticCollector实例以及通过JavaCompiler的getStandardFileManager()方法得到一个StandardFileManager对象 最后通过CompilationTask中的call方法编译源程序 在使用这种方法调用Java编译时最复杂的方法就是getTask 下面让我们讨论一下getTask方法 这个方法有如下所示的 个参数

getTask(Writer out JavaFileManager fileManager DiagnosticListener<? super JavaFileObject> diagnosticListener Iterable<String> options Iterable<String> classes Iterable<? extends JavaFileObject> pilationUnits)   这些参数大多数都可为null 它们的含义所下    ·out: 用于输出错误的流 默认是System err    ·fileManager: 标准的文件管理    ·diagnosticListener: 编译器的默认行为    ·options: 编译器的选项   ·classes 参与编译的class    最后一个参数pilationUnits不能为null 因为这个对象保存了你想编译的Java文件    在使用完getTask后 需要通过StandardJavaFileManager的getJavaFileObjectsFromFiles或getJavaFileObjectsFromStrings方法得到pilationUnits对象 调用这两个方法的方式如下 Iterable<? extends JavaFileObject> getJavaFileObjectsFromFiles(Iterable<? extends File> files)Iterable<? extends JavaFileObject> getJavaFileObjectsFromStrings(Iterable<String> names)String[] filenames = …;Iterable<? extends JavaFileObject> pilationUnits =fileManager getJavaFileObjectsFromFiles(Arrays asList(filenames));JavaCompiler CompilationTask task = piler getTask(null fileManager diagnostics options null pilationUnits);   最后需要关闭fileManager close();   下面是一个完整的演示程序 import java io *;import java util *;import javax tools *;public class test_pilerapi  private static void pilejava() throws Exception     JavaCompiler piler = ToolProvider getSystemJavaCompiler();   // 建立DiagnosticCollector对象    DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<JavaFileObject>();    StandardJavaFileManager fileManager = piler getStandardFileManager(diagnostics null null);   // 建立用于保存被编译文件名的对象   // 每个文件被保存在一个从JavaFileObject继承的类中    Iterable<? extends JavaFileObject> pilationUnits =            fileManager getJavaFileObjectsFromStrings(Arrays asList( test java ));   JavaCompiler CompilationTask task = piler getTask(null fileManager             diagnostics null null pilationUnits);   // 编译源程序   boolean success = task call();   fileManager close();   System out println((success)? 编译成功 : 编译失败 );    public static void main(String args[]) throws Exception     pilejava();     如果想得到具体的编译错误 可以对Diagnostics进行扫描 代码如下 for (Diagnostic diagnostic : diagnostics getDiagnostics())System out printf( Code: %s%n + Kind: %s%n + Position: %s%n + Start Position: %s%n + End Position: %s%n + Source: %s%n + Message: %s%n diagnostic getCode() diagnostic getKind() diagnostic getPosition() diagnostic getStartPosition() diagnostic getEndPosition() diagnostic getSource() diagnostic getMessage(null));   被编译的test java代码如下 public class test  public static void main(String[] args) throws Exception     aa; //错误语句   System out println( JavaCompiler测试成功! );     在这段代码中多写了个aa 得到的编译错误为 Code: piler err not stmtKind: ERRORPosition: Start Position: End Position: Source: test javaMessage: test java: : 不是语句Success: false   通过JavaCompiler进行编译都是在当前目录下生成 class文件 而使用编译选项可以改变这个默认目录 编译选项是一个元素为String类型的Iterable集合 如我们可以使用如下代码在D盘根目录下生成 class文件 Iterable<String> options = Arrays asList( d d:\\\\ );JavaCompiler CompilationTask task = piler getTask(null fileManager diagnostics options null pilationUnits);

  在上面的例子中options处的参数为null 而要传递编译器的参数 就需要将options传入    有时我们编译一个Java源程序文件 而这个源程序文件需要另几个Java文件 而这些Java文件又在另外一个目录 那么这就需要为编译器指定这些文件所在的目录 Iterable<String> options = Arrays asList( sourcepath d:\\\\src );   上面的代码指定的被编译Java文件所依赖的源文件所在的目录

  三 从内存中编译   JavaCompiler不仅可以编译硬盘上的Java文件 而且还可以编译内存中的Java代码 然后使用reflection来运行它们 我们可以编写一个JavaSourceFromString类 通过这个类可以输入Java源代码 一但建立这个对象 你可以向其中输入任意的Java代码 然后编译和运行 而且无需向硬盘上写 class文件

import java lang reflect *;import java io *;import javax tools *;import javax tools JavaCompiler CompilationTask;import java util *;import *;public class test_pilerapi  private static void pilerJava() throws Exception     JavaCompiler piler = ToolProvider getSystemJavaCompiler();   DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<JavaFileObject>();   // 定义一个StringWriter类 用于写Java程序   StringWriter writer = new StringWriter();   PrintWriter out = new PrintWriter(writer);   // 开始写Java程序   out println( public class HelloWorld );   out println( public static void main(String args[]) );   out println( System out println(\\ Hello World\\ ); );   out println( );   out println( );   out close();   //为这段代码取个名子 HelloWorld 以便以后使用reflection调用   JavaFileObject file = new JavaSourceFromString( HelloWorld writer toString());   Iterable<? extends JavaFileObject> pilationUnits = Arrays asList(file);   JavaCompiler CompilationTask task = piler getTask(null null     diagnostics null null pilationUnits);   boolean success = task call();   System out println( Success: + success);   // 如果成功 通过reflection执行这段Java程序   if (success)       System out println( 输出 );    Class forName( HelloWorld ) getDeclaredMethod( main new Class[]             String[] class ) invoke(null new Object[]             null );    System out println( 输出 );       public static void main(String args[]) throws Exception     pilerJava();  // 用于传递源程序的JavaSourceFromString类class JavaSourceFromString extends SimpleJavaFileObject  final String code;  JavaSourceFromString(String name String code)     super(URI create( string:/// + name replace( / )+ Kind SOURCE extension) Kind SOURCE);   de = code;    @Override  public CharSequence getCharContent(boolean ignoreEncodingErrors)     return code;  cha138/Article/program/Java/JSP/201311/19545

相关参考

知识大全 SE6调用编译器的两种方法[1]

Java进阶:SE6调用编译器的两种方法[1]  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  在

知识大全 在SE6中调用编译器的两种方法[4]

Java进阶:在SE6中调用编译器的两种方法[4]  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! 

知识大全 在SE6中调用编译器的两种方法[3]

Java进阶:在SE6中调用编译器的两种方法[3]  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! 

知识大全 在SE6中调用编译器的两种方法[2]

Java进阶:在SE6中调用编译器的两种方法[2]  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! 

知识大全 在SE6中调用编译器的两种方法[1]

Java进阶:在SE6中调用编译器的两种方法[1]  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! 

知识大全 Java调用Eclipse的编译器JDT

Java调用Eclipse的编译器JDT  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  想给项目

知识大全 Java与Oracle的两种连接方式

Java与Oracle的两种连接方式  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  第一种方式通

知识大全 介绍java 产生随机数的两种方式

   在java中我们可以通过两种方式来获取随机数(generatingarandomnumber)一种是大家熟悉的javalangMathRandom()静态方法另一种

知识大全 java读取网站内容的两种方法

  HttpClient  利用apache的虚拟客户端包获取某个地址的内容 importjavaioUnsupportedEncodingException;  importjavauti

知识大全 开发JAVA编程中字符串分割的两种方法

开发JAVA编程中字符串分割的两种方法  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  方法:采用