知识大全 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相关参考
Java进阶:SE6调用编译器的两种方法[1] 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! 在
Java进阶:在SE6中调用编译器的两种方法[4] 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!
Java进阶:在SE6中调用编译器的两种方法[3] 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!
Java进阶:在SE6中调用编译器的两种方法[2] 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!
Java进阶:在SE6中调用编译器的两种方法[1] 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!
Java调用Eclipse的编译器JDT 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! 想给项目
Java与Oracle的两种连接方式 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! 第一种方式通
在java中我们可以通过两种方式来获取随机数(generatingarandomnumber)一种是大家熟悉的javalangMathRandom()静态方法另一种
HttpClient 利用apache的虚拟客户端包获取某个地址的内容 importjavaioUnsupportedEncodingException; importjavauti
开发JAVA编程中字符串分割的两种方法 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! 方法:采用