介绍

java5之前我们可以通过java提供的tools.jar来操作java编译器,java6提供了新的API,让我们可以更方便的调用。包名为javax.tools。

使用

通过文件编译

String filePath = "D:\\Client.java";

//获取java编译器

JavaCompiler javaCompiler = ToolProvider.getSystemJavaCompiler();

//编译

int result = javaCompiler.run(null, null, null, filePath);

System.out.println(result);

结果为0表示编译成功,在相同目录下生成了Client.class文件。

编译参数依次为

java编译器提供参数,如果为null,以System.in代替

得到Java编译器的输出信息,如果为null,以System.out代替

接收编译器的错误信息,如果为null,以System.err代替

一个或多个Java源程式文件

通过非文件格式编译

java还提供了编译其他形式的源文件的功能,如内存字符串文本,数据库读取的文本。

public class JavaFileManagerMain {

public static void main(String[] args) {

//文件路径

String fullQuanlifiedFileName = "D:\\Client.java";

//获取编译器

JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();

//获取文件管理器 参数依次为错误监听器,区域对象,编码

StandardJavaFileManager fileManager =

compiler.getStandardFileManager(null, null, null);

//通过文件全路径获取要编译的文件对象

Iterable extends JavaFileObject> files =

fileManager.getJavaFileObjectsFromStrings(

Arrays.asList(fullQuanlifiedFileName));

//创建编译任务 参数为错误输出流,文件管理器,错误处理器,编译器选项,参与编译的class,带编译的java文件

JavaCompiler.CompilationTask task = compiler.getTask(

null, fileManager, null, null, null, files);

//执行任务

Boolean result = task.call();

if (result) {

System.out.println("Succeeded");

}

}

}

接下来实现从内存中读取待编译对象

public class StringObject extends SimpleJavaFileObject {

private String content = null;

protected StringObject(String className, String contents) throws URISyntaxException {

super(new URI(className), Kind.SOURCE);

this.content = contents;

}

@Override

public CharSequence getCharContent(boolean ignoreEncodingErrors) {

return content;

}

}

public class StringClassCompilerMain {

public static void main(String[] args) {

JavaCompiler javaCompiler = ToolProvider.getSystemJavaCompiler();

StandardJavaFileManager standardJavaFileManager = javaCompiler.getStandardFileManager(null, null, null);

JavaFileObject testFile = generateTest();

Iterable extends JavaFileObject> classes = Arrays.asList(testFile);

JavaCompiler.CompilationTask task = javaCompiler.getTask(null, standardJavaFileManager, null, null, null, classes);

if (task.call()) {

System.out.println("success");

} else {

System.out.println("failure!");

}

}

//通过字符串创建一个待编译对象

private static JavaFileObject generateTest() {

String contents = "package com.imooc.sourcecode.java.javacompile.test3;" +

"class Test {\n" +

" public static void main(String[] args) {\n" +

" System.out.println(\"success\");\n" +

" }\n" +

"}\n";

StringObject so = null;

try {

so = new StringObject("com.imooc.sourcecode.java.javacompile.test3.Test", contents);

} catch (URISyntaxException e) {

e.printStackTrace();

}

return so;

}

}

结果编译成功。

实现在运行期编译及加载类

定义源代码存储类

/**

* 待编译对象 存储待编译的字符串

*/

public class JavaSourceFileObject extends SimpleJavaFileObject {

//表示java源代码

private CharSequence content;

protected JavaSourceFileObject(String className, String content) {

super(URI.create("string:///" + className.replaceAll("\\.", "/") + Kind.SOURCE.extension), Kind.SOURCE);

this.content = content;

}

/**

* 获取需要编译的源代码

*

* @param ignoreEncodingErrors

* @return

* @throws IOException

*/

@Override

public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {

return content;

}

}

定义编译结果存储类

/**

* 存储编译之后的class内容

*/

public class JavaTargetFileObject extends SimpleJavaFileObject {

/**

* Compiler编译后的byte数据会存在这个ByteArrayOutputStream对象中,

* 后面可以取出,加载到JVM中。

*/

private ByteArrayOutputStream byteArrayOutputStream;

public JavaTargetFileObject(String className, Kind kind) {

super(URI.create("string:///" + className.replaceAll("\\.", "/") + kind.extension), kind);

this.byteArrayOutputStream = new ByteArrayOutputStream();

}

/**

* 覆盖父类SimpleJavaFileObject的方法。

* 该方法提供给编译器结果输出的OutputStream。

*

* 编译器完成编译后,会将编译结果输出到该 OutputStream 中,我们随后需要使用它获取编译结果

*

* @return

* @throws IOException

*/

@Override

public OutputStream openOutputStream() throws IOException {

return this.byteArrayOutputStream;

}

/**

* FileManager会使用该方法获取编译后的byte,然后将类加载到JVM

*/

public byte[] getBytes() {

return this.byteArrayOutputStream.toByteArray();

}

}

定义自己的文件管理器

/**

* 内存文件管理器

* @see JavaTargetFileObject

*/

public class ClassFileManager extends ForwardingJavaFileManager {

/**

* 存储编译后的代码数据

*/

private JavaTargetFileObject classJavaFileObject;

protected ClassFileManager(JavaFileManager fileManager) {

super(fileManager);

}

/**

* 编译后加载类

*

* 返回一个匿名的SecureClassLoader:

* 加载由JavaCompiler编译后,保存在ClassJavaFileObject中的byte数组。

*/

@Override

public ClassLoader getClassLoader(Location location) {

return new SecureClassLoader() {

@Override

protected Class> findClass(String name) throws ClassNotFoundException {

byte[] bytes = classJavaFileObject.getBytes();

return super.defineClass(name, bytes, 0, bytes.length);

}

};

}

/**

* 给编译器提供JavaClassObject,编译器会将编译结果写进去

*/

@Override

public JavaFileObject getJavaFileForOutput(Location location, String className, JavaFileObject.Kind kind, FileObject sibling)

throws IOException {

this.classJavaFileObject = new JavaTargetFileObject(className, kind);

return this.classJavaFileObject;

}

}

定义一个实现类编译和加载

/**

* 运行时编译

*/

public class DynamicCompiler {

private JavaFileManager fileManager;

public DynamicCompiler() {

this.fileManager = initManger();

}

private JavaFileManager initManger() {

if (fileManager != null) {

return fileManager;

} else {

JavaCompiler javaCompiler = ToolProvider.getSystemJavaCompiler();

DiagnosticCollector diagnosticCollector = new DiagnosticCollector<>();

fileManager = new ClassFileManager(javaCompiler.getStandardFileManager(diagnosticCollector, null, null));

return fileManager;

}

}

/**

* 编译源码并加载,获取Class对象

*

* @param fullName

* @param sourceCode

* @return

* @throws ClassNotFoundException

*/

public Class compileAndLoad(String fullName, String sourceCode) throws ClassNotFoundException {

JavaCompiler javaCompiler = ToolProvider.getSystemJavaCompiler();

List javaFileObjectList = new ArrayList<>();

javaFileObjectList.add(new JavaSourceFileObject(fullName, sourceCode));

boolean result = javaCompiler

.getTask(null, fileManager, null, null, null, javaFileObjectList)

.call();

if (result) {

return this.fileManager.getClassLoader(null).loadClass(fullName);

} else {

return Class.forName(fullName);

}

}

/**

* 关闭fileManager

*

* @throws IOException

*/

public void close() throws IOException {

this.fileManager.close();

}

}

java compile_java中的CompileAPI入门及使用相关推荐

  1. Java快速入门学习笔记9 | Java语言中的方法

    有人相爱,有人夜里开车看海,有人却连LeetCode第一题都解不出来!虽然之前系统地学习过java课程,但是到现在一年多没有碰过Java的代码,遇到LeetCode不知是喜是悲,思来想去,然后清空自己 ...

  2. Java快速入门学习笔记8 | Java语言中的数组

    有人相爱,有人夜里开车看海,有人却连LeetCode第一题都解不出来!虽然之前系统地学习过java课程,但是到现在一年多没有碰过Java的代码,遇到LeetCode不知是喜是悲,思来想去,然后清空自己 ...

  3. Java快速入门学习笔记7 | Java语言中的类与对象

    有人相爱,有人夜里开车看海,有人却连LeetCode第一题都解不出来!虽然之前系统地学习过java课程,但是到现在一年多没有碰过Java的代码,遇到LeetCode不知是喜是悲,思来想去,然后清空自己 ...

  4. Java快速入门学习笔记3 | Java语言中的表达式与操作符

    有人相爱,有人夜里开车看海,有人却连LeetCode第一题都解不出来!虽然之前系统地学习过java课程,但是到现在一年多没有碰过Java的代码,遇到LeetCode不知是喜是悲,思来想去,然后清空自己 ...

  5. Java快速入门学习笔记2 | Java语言中的基本类型

    有人相爱,有人夜里开车看海,有人却连LeetCode第一题都解不出来!虽然之前系统地学习过java课程,但是到现在一年多没有碰过Java的代码,遇到LeetCode不知是喜是悲,思来想去,然后清空自己 ...

  6. java语言中解释方式是什么意思,Java语言快速入门·简答T

    1 面向对象与面向过程有什么区别? 面向对象编程:既然面向的是对象,那么强调的自然就是--对象,那么对象多了,就会抽象出相应的类(对象是类的实例化),所以 · 程序是由类组成 · 程序运行的时候去调用 ...

  7. 【网络安全入门大总结】—Java语言中常用的渗透漏洞大汇总

    Java语言中常用的漏洞大汇总,建议收藏. 准备好,上课了~~~ 目录 Servlet 简介 生命周期为 接口 Struts 2 . 简介 请求流程 相关CVE Spring 简介 Spring MV ...

  8. java中的网络入门2(J2SE入门19)

    建立TCP客户端  创建一个TCP客户端程序的步骤:     1). 创建Socket     2). 获得I/O流     3). 对I/O流进行读写操作     4). 关闭I/O流     5) ...

  9. Java面试宝典简洁篇(持续更新中,从入门到放弃)

    Java基础 1.Hashcode()和 equals()和==区别?  1.hashcode()方法跟 equals()在 java 中都是判断两个对象是否相等 2.两个对象相同,则 hashcod ...

最新文章

  1. Jfinal 2.1版本,JFinalConfig里自动配置路由的代码实现,直接晒代码
  2. 整理了一个castle的文档,供大家学习使用
  3. Python_note5 函数和代码复用+PyInstaller库+数码管绘制
  4. php根据宽度显示html,我怎样才能动态地改变PHP的HTML div的宽度?
  5. 笑谈在工作中树立个人品牌的十大原则的个人观点
  6. IOS Unit test
  7. cisco 交换机通过console 导入 IOS
  8. php上传文件损坏,PHP 上传文件故障排除
  9. 结合 category 工作原理分析 OC2.0 中的 runtime
  10. Java 中的悲观锁、乐观锁、自旋锁、适应性自旋锁、偏向锁、轻量级锁、重量级锁、公平锁、非公平锁、可重入锁、共享锁等
  11. Wireshark工作笔记-对TCP连接与断开以及数据传输的实战分析
  12. 谈Flash中的鼠标响应
  13. 标准c语言有几个关键字,C语言有多少个关键字
  14. ZR_DJYVP2阻燃型计算机电缆,阻燃计算机电缆ZR-DJYVP 1*3*1.5
  15. 关于jdbc连接mysql的问题bug
  16. [LeetCode]50.Pow(x, n)
  17. Python 对象的绑定方法
  18. 美联储数字货币最新进展
  19. 移动硬盘插入提示需要格式化RAW_分区变成RAW格式怎么办?手把手教你解决方法...
  20. 关于NoSQL与SQL的区别

热门文章

  1. javascript第三天(2)
  2. SpringMVC的filter怎么使用Autowired依赖注入bean
  3. Linux系统基础.作业
  4. Android中attrs.xml文件的使用详解
  5. linux --- 基础指令
  6. 操作系统 --- 进程和管程的不同
  7. es6 --- Proxy的属性(get、set除外)
  8. 关于java中BufferedReader的read()及readLine()方法的使用心得
  9. Android SimpleAdapter的参数
  10. Ubuntu GNOME 15.10升级16.4LTS