当前位置: 首页 > news >正文

java文件编译_通过代码如何编译java文件

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则默认为:http://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);

}

}1

2

3

4

5

6

7

1

2

3

4

5

6

7

执行结果(由于输出信息没有指定,默认打印在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 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 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文件。

相关文章:

  • java long时间_Java 日期时间 Date类型,long类型,String类型表现形式的转换
  • java pkcs7 pem_RSA私钥和公钥文件格式 (pkcs#7, pkcs#8, pkcs#12, pem)
  • java long integer_java Long、Integer 、Double、Boolean类型 不能直接比较
  • java response 调用js_java httpclient 请求的response为text/javascript,如何处理响应的js对象?...
  • java doublebuffer_Java中的DoubleBufferallocate()方法
  • 银联数据服务中心java工程师面试_中国银联JAVA开发工程师面试经验|面试题 - 职朋职业圈...
  • java调用datastage_Datastage重启服务
  • mysql中mapping标签的作用_MyBatis全局配置文件标签详解
  • python编写字典库_Python绘图Turtle库详解
  • go解析mysql binlog_一个应用它提取MySQL binlog,解析binlog并将增量更新数据推送到不同的接收器...
  • java运行时读取注解_Java自定义注解和运行时靠反射获取注解
  • java long polling_如何在Spring Boot应用程序中实现Long Polling REST endpoints ?
  • java获取其他线程的错误_java多线程开发容易犯的错误
  • java 检索数据_java代码实现搜索elasticsearch索引数据
  • java非异步线程池_Spring Boot利用@Async异步调用:ThreadPoolTaskScheduler线程池的优雅关闭详解...
  • 《剑指offer》分解让复杂问题更简单
  • 【译】理解JavaScript:new 关键字
  • 2018以太坊智能合约编程语言solidity的最佳IDEs
  • Android Volley源码解析
  • Angular6错误 Service: No provider for Renderer2
  • C# 免费离线人脸识别 2.0 Demo
  • C学习-枚举(九)
  • Docker下部署自己的LNMP工作环境
  • ES学习笔记(12)--Symbol
  • JavaScript 奇技淫巧
  • Java教程_软件开发基础
  • mysql innodb 索引使用指南
  • Node.js 新计划:使用 V8 snapshot 将启动速度提升 8 倍
  • PHP的类修饰符与访问修饰符
  • python3 使用 asyncio 代替线程
  • Vue 动态创建 component
  • 给初学者:JavaScript 中数组操作注意点
  • 构造函数(constructor)与原型链(prototype)关系
  • 规范化安全开发 KOA 手脚架
  • 聊聊redis的数据结构的应用
  • 浏览器缓存机制分析
  • 世界上最简单的无等待算法(getAndIncrement)
  • 详解NodeJs流之一
  • 译自由幺半群
  • Prometheus VS InfluxDB
  • ​iOS安全加固方法及实现
  • ​Z时代时尚SUV新宠:起亚赛图斯值不值得年轻人买?
  • ​总结MySQL 的一些知识点:MySQL 选择数据库​
  • # Maven错误Error executing Maven
  • #Linux(权限管理)
  • #NOIP 2014# day.1 T2 联合权值
  • #我与Java虚拟机的故事#连载10: 如何在阿里、腾讯、百度、及字节跳动等公司面试中脱颖而出...
  • $refs 、$nextTic、动态组件、name的使用
  • (Redis使用系列) Springboot 在redis中使用BloomFilter布隆过滤器机制 六
  • (二) Windows 下 Sublime Text 3 安装离线插件 Anaconda
  • (二)斐波那契Fabonacci函数
  • (原創) 如何動態建立二維陣列(多維陣列)? (.NET) (C#)
  • (转)IIS6 ASP 0251超过响应缓冲区限制错误的解决方法
  • (转载)(官方)UE4--图像编程----着色器开发
  • .NET Core中的去虚