Java进阶:SE6调用编译器的两种方法[1]

在第一部分我们讨论调用java编译器的最容易的方法 这种方法可以很好地工作 但它确不能更有效地得到我们所需要的信息 如标准的输入 输出信息 而在Java SE 中最好的方法是使用StandardJavaFileManager类 这个类可以很好地控制输入 输出 并且可以通过DiagnosticListener得到诊断信息 而DiagnosticCollector类就是...
Java进阶:SE6调用编译器的两种方法[1]
  在很多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 PrintStream
  System 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 diagnosticListener   Iterable options   Iterable classes   Iterable pilationUnits)
  这些参数大多数都可为null 它们的含义所下
  ·out: 用于输出错误的流 默认是System err
  ·fileManager: 标准的文件管理
  ·diagnosticListener: 编译器的默认行为
  ·options: 编译器的选项
  ·classes 参与编译的class
  最后一个参数pilationUnits不能为null 因为这个对象保存了你想编译的Java文件
  在使用完getTask后 需要通过StandardJavaFileManager的getJavaFileObjectsFromFiles或getJavaFileObjectsFromStrings方法得到pilationUnits对象 调用这两个方法的方式如下
  Iterable getJavaFileObjectsFromFiles(  Iterable files)  Iterable getJavaFileObjectsFromStrings(  Iterable names)  String[] filenames = …;  Iterable 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 diagnostics = new DiagnosticCollector();   StandardJavaFileManager fileManager = piler getStandardFileManager(diagnostics null null);   // 建立用于保存被编译文件名的对象   // 每个文件被保存在一个从JavaFileObject继承的类中   Iterable 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 stmt  Kind: ERROR  Position:   Start Position:   End Position:   Source: test java  Message: test java: : 不是语句  Success: false
  通过JavaCompiler进行编译都是在当前目录下生成 class文件 而使用编译选项可以改变这个默认目录 编译选项是一个元素为String类型的Iterable集合 如我们可以使用如下代码在D盘根目录下生成 class文件
  Iterable options = Arrays asList( d d:\\ );  JavaCompiler CompilationTask task = piler getTask(null fileManager   diagnostics options null pilationUnits);
  在上面的例子中options处的参数为null 而要传递编译器的参数 就需要将options传入
  有时我们编译一个Java源程序文件 而这个源程序文件需要另几个Java文件 而这些Java文件又在另外一个目录 那么这就需要为编译器指定这些文件所在的目录
  Iterable options = Arrays asList( sourcepath d:\\src );
  上面的代码指定的被编译Java文件所依赖的源文件所在的目录
lishixinzhi/Article/program/Java/hx/201311/27239
2022-11-23
mengvlog 阅读 5 次 更新于 2025-07-19 23:47:59 我来答关注问题0
  • JavaCompiler中最核心的方法是run 通过这个方法可以编译java源程序 这个方法有 个固定参数和 个可变参数(可变参数是从Jave SE 开始提供的一个新的参数类型 用type… argu表示) 前 个参数分别用来为java编译器提供参数 得到Java编译器的输出信息以及接收编译器的错误信息 后面的可变参数可以传入一个或多...

  • 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 diagnostics = new DiagnosticCollector(); Standard...

  • 能够从应用程序内部对类进行编译这一实现使得代码生成具有了交互性-我可以以交互方式来修改和构建类。为了支持Java脚本编程,Java SE 6支持JSR 223,这是一种提供了到Java内部进行存取的脚本语言的框架标准。你可以定位脚本引擎并且在运行时调用它们以运行脚本。该脚本编程API允许你为选择的脚本语言提供Java...

  •  翡希信息咨询 Java (TM) SE Runtime Enrironment 6 Update 是什么程序?

    Java ™ SE Runtime Environment 6 Update 是Java标准版6的升级程序。以下是关于该程序的详细解释:JAVA™:这是Java的注册商标,表示该程序与Java技术相关。SE:代表Standard Edition,即标准版。Java SE是Java平台的标准版本,适用于桌面和服务器环境。Runtime Environment:即运行环境。Java S...

  •  翡希信息咨询 如何解决OSX 10.11系统中Java SE 6的兼容性问题?

    要解决OSX 10.11系统中Java SE 6的兼容性问题,最直接且有效的方法是升级到最新版的Java SE 8,并进行以下配置:确认当前Java版本:在终端中执行java version命令,查看当前Java版本。如果已安装Java SE 8,则无需进行后续步骤。更新Java配置:使用sudo vim /Library/Java/JavaVirtualMachines/jdk1.8....

檬味博客在线解答立即免费咨询

Java相关话题

Copyright © 2023 WWW.MENGVLOG.COM - 檬味博客
返回顶部