Java千百问_08JDK详解(008)_通过代码如何编译java文件
2016-06-19 07:19
711 查看
点击进入_更多_Java千百问
在Java 6之后,提供了标准包来操作Java编译器,这就是javax.tools包。我们使用这个包中的API以及其他辅助包可以定制自己的编译器。通过ToolProvider类的源码我们可以看到,javax.tools这个包中的API最终都是通过tools.jar中的com.sun.tools.javac包来调用Java编译器的。
通过代码编译java大体有如下三种方式,灵活运用这几种方式可以DIY属于自己的编译器:
通过JavaCompiler.run()
最简单的用法即使用JavaCompiler类的run方法,前3个参数分别为:输入信息、输出信息、错误信息,如果为null则默认为:System.in、System.out、System.err。最后一个参数为javac后的命令文本,例如传入Test.java,则等同于在终端执行javac Test.java。
例如:
执行结果(由于输出信息没有指定,默认打印在System.out中):
javac 1.7.0_79
===0
通过JavaCompiler.getTask()编译硬盘中代码
使用JavaCompiler.run方法非常简单,但它确不能更有效地得到我们所需要的信息。一般来说我们都会使用StandardJavaFileManager类(jdk 6或以上),这个类可以很好地控制输入、输出,并且可以通过DiagnosticListener得到诊断信息,而DiagnosticCollector类就是listener(监听)的实现。
具体实例如下:
运行结果如下:
编译成功
在对应路径下会发现com/test/Test.class文件(Test的包是package com.test,所以会自动在对应目录下生成com/test/路径)。
通过JavaCompiler .getTask()编译内存中代码
JavaCompiler不仅可以编译硬盘上的Java文件,而且还可以编译内存中的Java代码,然后使用reflection来运行它们。我们可以编写一个JavaSourceFromString类,通过这个类可以输入Java源代码。
具体实例如下:
运行结果如下:
编译成功
在对应路径下会发现HelloWorld.class文件。
1、通过代码如何编译java文件
编译器是一个命令行工具(jdk自带的编译工具javac,了解javac看这里:javac是什么),但也可以使用API来调用(一般的IDE都会使用这一组API来封装自己的编译功能)。编译器遵循Java语言规范(The Java Language Specification,JLS)和Java虚拟机规范(The Java Virtual Machine Specification,JVMS)。在Java 6之后,提供了标准包来操作Java编译器,这就是javax.tools包。我们使用这个包中的API以及其他辅助包可以定制自己的编译器。通过ToolProvider类的源码我们可以看到,javax.tools这个包中的API最终都是通过tools.jar中的com.sun.tools.javac包来调用Java编译器的。
通过代码编译java大体有如下三种方式,灵活运用这几种方式可以DIY属于自己的编译器:
通过JavaCompiler.run()
最简单的用法即使用JavaCompiler类的run方法,前3个参数分别为:输入信息、输出信息、错误信息,如果为null则默认为:System.in、System.out、System.err。最后一个参数为javac后的命令文本,例如传入Test.java,则等同于在终端执行javac Test.java。
例如:
public class Test { public static void main(String[] args) throws Exception { JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); int run = compiler.run(null, null, null, "-version"); System.out.println("===" + run); } }
执行结果(由于输出信息没有指定,默认打印在System.out中):
javac 1.7.0_79
===0
通过JavaCompiler.getTask()编译硬盘中代码
使用JavaCompiler.run方法非常简单,但它确不能更有效地得到我们所需要的信息。一般来说我们都会使用StandardJavaFileManager类(jdk 6或以上),这个类可以很好地控制输入、输出,并且可以通过DiagnosticListener得到诊断信息,而DiagnosticCollector类就是listener(监听)的实现。
具体实例如下:
public class Test { public static void main(String[] args) throws Exception { Test.compiler(); } public static void compiler() throws IOException { JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); // 建立DiagnosticCollector对象 DiagnosticCollector diagnostics = new DiagnosticCollector(); StandardJavaFileManager fileManager = compiler.getStandardFileManager(diagnostics, null, null); // 建立源文件对象,每个文件被保存在一个从JavaFileObject继承的类中 Iterable<? extends JavaFileObject> compilationUnits = fileManager.getJavaFileObjectsFromStrings(Arrays .asList("/Users/sunjie/Desktop/works/workspace/my-test/src/com/test/Test.java")); // options命令行选项 Iterable<String> options = Arrays.asList("-d", "/Users/sunjie/Desktop/works/workspace/my-test/src/com/test/classes");// 指定的路径一定要存在,javac不会自己创建文件夹 JavaCompiler.CompilationTask task = compiler.getTask(null, fileManager, diagnostics, options, null, compilationUnits); // 编译源程序 boolean success = task.call(); fileManager.close(); System.out.println((success) ? "编译成功" : "编译失败"); // 打印信息 for (Object object : diagnostics.getDiagnostics()) { Diagnostic diagnostic = (Diagnostic) object; 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)); } } }
运行结果如下:
编译成功
在对应路径下会发现com/test/Test.class文件(Test的包是package com.test,所以会自动在对应目录下生成com/test/路径)。
通过JavaCompiler .getTask()编译内存中代码
JavaCompiler不仅可以编译硬盘上的Java文件,而且还可以编译内存中的Java代码,然后使用reflection来运行它们。我们可以编写一个JavaSourceFromString类,通过这个类可以输入Java源代码。
具体实例如下:
public class Test { public static void main(String[] args) throws Exception { Test.compiler2(); } public static void compiler2() throws IOException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException, ClassNotFoundException { JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); DiagnosticCollector diagnostics = new DiagnosticCollector(); // 定义一个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(); StandardJavaFileManager fileManager = compiler.getStandardFileManager(diagnostics, null, null); // 为这段代码取个名子:HelloWorld SimpleJavaFileObject file = (new Test()).new JavaSourceFromString("HelloWorld", writer.toString()); Iterable compilationUnits = Arrays.asList(file); // options命令行选项 Iterable<String> options = Arrays.asList("-d", "/Users/sunjie/Desktop/works/workspace/my-test/src/com/test/classes");// 指定的路径一定要存在,javac不会自己创建文件夹 JavaCompiler.CompilationTask task = compiler.getTask(null, fileManager, diagnostics, options, null, compilationUnits); boolean success = task.call(); System.out.println((success) ? "编译成功" : "编译失败"); } // 用于传递源程序的JavaSourceFromString类 class JavaSourceFromString extends SimpleJavaFileObject { final String code; JavaSourceFromString(String name, String code) { super(URI.create("string:///" + name.replace('.', '/') + Kind.SOURCE.extension), Kind.SOURCE); this.code = code; } @Override public CharSequence getCharContent(boolean ignoreEncodingErrors) { return code; } } }
运行结果如下:
编译成功
在对应路径下会发现HelloWorld.class文件。
相关文章推荐
- AOP编程简介及其在Spring框架中的使用
- 手把手教你整合最优雅SSM框架:SpringMVC + Spring + MyBatis
- 开山篇
- JAVA、OC的内存管理机制的本质
- JAVA集合框架Collection
- [Java] 继承中,父类被覆盖的成员变量、方法的可访问性
- Java File类的介绍
- Java动态编程之javassist
- java 高并发
- java 设计模式 之 桥接
- 深度剖析JDK动态代理机制
- Spring Boot实现跨域访问实现代码
- eclipse配置汉字乱码
- eclipse配置PHP开发环境
- Java静态代理和jdk动态代理、Cglib动态代理
- java web session management
- Maven插件:maven-javadoc-plugin
- NIO(一):Java NIO概述
- Java中堆内存和栈内存详解
- Java垃圾回收机制