-
2021-02-12 10:59:45
引言
近期在做Android相关开发工作,不可避免的需要接触Java层的调用机制,好多年不用Java了,这里整理下相关的编译命令。作为后续参考使用,也防止每次都需要到处查找。
基本概念
javac - Java programming language compiler,Java编译器,类似gcc
java - the Java Application Launcher,Java程序加载器,类似操作系统的进程加载器(Loader)
jdb - Java Application Debugger,调试器,类似gdb
javah - C Header and Stub File Generator,JNI头文件生成器
javap - Class File Disassembler,Java反编译工具
javadoc - API Documentation Generator,Java文档自动生成器
jar - JAR Archive Tool,Java库文件工具,类似ar
常规的编译、链接、运行,只需要了解javac、jar、java即可。需要调试可以参考jdb。
编译(.java-->.class)
javac a.java a.class
生成Jar包(.class-->.jar)
jar cf myFile.jar *.class
从Jar包中提取*.class
jar xf myFile.jar
运行java程序
java my.class
更具体的用法建议参考java的用户手册。
java反编译工具Jad
先从http://www.kpdus.com/jad.html下载jad软件。解压之后可以直接使用,放到${jad_home}中。
[jad_home]/jad.exe -r -ff -d src -s java classes/**/*.class
其中-r 表示恢复源文件的目录结构,,-ff 表示将类属性定义放在类方法定义之前, -d 表示输出目录,-s 表示文件的扩展名。
所有的java文件将会被放置到src目录下。
更详细的用法可以参考下载文件中的Readme.txt。
更多相关内容 -
java Compiler API (java编译api)
2019-05-23 09:59:50在早期的版本中(Java SE5及以前版本)中只能通过tools.jar中的com.sun.tools.javac包来调用Java编译器,但由于tools.jar不是标准的Java库,在使用时必须要设置这...使用Java API来编译Java源代码有非常多方法,目前让...在早期的版本中(Java SE5及以前版本)中只能通过tools.jar中的
com.sun.tools.javac
包来调用Java编译器,但由于tools.jar
不是标准的Java库,在使用时必须要设置这个jar的路径。而在Java SE6中为我们提供了标准的包来操作Java编译器,这就是javax.tools
包。编译java文件
使用Java API来编译Java源代码有非常多方法,目前让我们来看一种最简单的方法,通过JavaCompiler进行编译。
使用
ToolProvider.getSystemJavaCompiler
来得到一个JavaCompiler
接口的实例。JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
JavaCompiler
中最核心的方法是run()
。通过这个方法能编译java源代码。int run(InputStream in, OutputStream out, OutputStream err, String... arguments)
参数分别用来为:
- java编译器提供参数
- 得到Java编译器的输出信息
- 接收编译器的错误信息,
- 一个或多个Java源程式文件
如果run编译成功,返回 0。
如果前3个参数传入的是
null
,那么run方法将以标准的输入、输出代替,即System.in
、System.out
和System.err
。如果我们要编译一个test.java
文件,并将使用标准输入输出,run的使用方法如下:int results = tool.run(null, null, null, "F:\\demo\\Test.java");
完整的例子:
//CompileMain.java import javax.tools.JavaCompiler; import javax.tools.ToolProvider; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; public class CompileMain { public static void main(String[] args) throws IOException { JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); int result = compiler.run(null, null, null, "F:\\demo\\Test.java"); System.out.println(result == 0 ? "编译成功" : "编译失败"); //执行java 命令 , 空参数, 所在文件夹 Process process = Runtime.getRuntime().exec("java Test",null,new File("F:\\demo\\")); BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream())); String str; while ((str = bufferedReader.readLine()) != null) { System.out.println(str); } } }
public class Test { public static void main(String[] args) { System.out.println("this is a test.java file ,thank you very much"); } }
$ javac CompileMain.java $ java CompileMain 编译成功 this is a test.java file ,thank you very much
编译非文件形式源代码
JDK 6 的编译器 API 的另外一个强大之处在于,它可以编译的源文件的形式并不局限于文本文件。
JavaCompiler
类依靠文件管理服务可以编译多种形式的源文件。比如直接由内存中的字符串构造的文件,或者是从数据库中取出的文件。这种服务是由JavaFileManager
类提供的。在Java SE6中最佳的方法是使用
StandardJavaFileManager
类。这个类能非常好地控制输入、输出,并且能通过DiagnosticListener
得到诊断信息,而DiagnosticCollector
类就是listener的实现。新的 JDK 定义了javax.tools.FileObject
和javax.tools.JavaFileObject
接口。任何类,只要实现了这个接口,就可以被JavaFileManager
识别。
使用
StandardJavaFileManager
步骤:- 建立一个
DiagnosticCollector
实例 - 通过
JavaCompiler.getStandardFileManager()
方法得到一个StandardFileManager
对象。 - 使用
StandardFileManager
获取需要编译的源代码。从文件或者字符流中获取源代码。 JavaCompiler.getTask()
生成编译任务抽象。- 通过
CompilationTask.call()
方法编译源代码。 - 关闭
StandardFileManager
。
在使用这种方法调用Java编译时最复杂的方法就是
getTask
,下面让我们讨论一下getTask
方法。这个方法有如下所示的6个参数。getTask(Writer out, JavaFileManager fileManager, DiagnosticListener<? super JavaFileObject> diagnosticListener, Iterable<String> options, Iterable<String> classes, Iterable<? extends JavaFileObject> compilationUnits)
这些参数大多数都可为
null
。他们的含义所下。out
: 用于输出错误的流,默认是System.err
。fileManager
:标准的文件管理。diagnosticListener
: 编译器的默认行为。options
: 编译器的选项classes
:参和编译的class。compilationUnits
: 待编译的Java文件,不能为null
。
CompilationTask
提供了setProcessors(Iterable<? extends Processor>processors)
方法,用户可以制定处理 annotation 的处理器。在使用完
getTask
前,需要通过StandardJavaFileManager.getJavaFileObjectsFromFiles()
或StandardJavaFileManager.getJavaFileObjectsFromStrings
方法得到待编译的compilationUnits
对象。也可以通过继承/实现
SimpleJavaObject
获取带编译的对象。调用这两个方法的方式如下:
Iterable<? extends JavaFileObject> getJavaFileObjectsFromFiles(Iterable<? extends File> files) Iterable<? extends JavaFileObject> getJavaFileObjectsFromStrings(Iterable<String> names) String[] filenames = …; Iterable<? extends JavaFileObject> compilationUnits = fileManager.getJavaFileObjectsFromFiles(Arrays.asList(filenames)); JavaCompiler.CompilationTask task = compiler.getTask(null, fileManager, diagnostics, options, null, compilationUnits);
最后需要关闭
fileManager.close()
;例如:
package win.hgfdodo.dynamic; import javax.tools.JavaCompiler; import javax.tools.JavaFileObject; import javax.tools.StandardJavaFileManager; import javax.tools.ToolProvider; import java.util.Arrays; public class JavaFileManagerMain { public static void main(String[] args) { String fullQuanlifiedFileName = "win.hgfdodo.dynamic.".replaceAll("\\.", java.io.File.separator) + "Calculator.java"; JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null); Iterable<? extends JavaFileObject> files = fileManager.getJavaFileObjectsFromStrings( Arrays.asList(fullQuanlifiedFileName)); JavaCompiler.CompilationTask task = compiler.getTask( null, fileManager, null, null, null, files); Boolean result = task.call(); if (result == true) { System.out.println("Succeeded"); } } }
package win.hgfdodo.dynamic; public class Calculator { public int multiply(int multiplicand, int multiplier) { return multiplicand * multiplier; } }
JavaFileObject获取java源程序
开发者希望生成
Calculator
的一个测试类,而不是手工编写。使用 compiler API,可以将内存中的一段字符串,编译成一个 CLASS 文件。定制 JavaFileObject 对象:
package win.hgfdodo.dynamic; import javax.tools.SimpleJavaFileObject; import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; 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) throws IOException { return content; } }
SimpleJavaFileObject
是JavaFileObject
的子类,它提供了默认的实现。继承SimpleJavaObject
之后,只需要实现getCharContent
方法。接下来,在内存中构造
Calculator
的测试类CalculatorTest
,并将代表该类的字符串放置到StringObject
中,传递给JavaCompiler.getTask
方法。具体如下:
package win.hgfdodo.dynamic; import javax.tools.JavaCompiler; import javax.tools.JavaFileObject; import javax.tools.StandardJavaFileManager; import javax.tools.ToolProvider; import java.net.URISyntaxException; import java.util.Arrays; 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 = new String( "package win.hgfdodo.dynamic;" + "class CalculatorTest {\n" + " public void testMultiply() {\n" + " Calculator c = new Calculator();\n" + " System.out.println(c.multiply(2, 4));\n" + " }\n" + " public static void main(String[] args) {\n" + " CalculatorTest ct = new CalculatorTest();\n" + " ct.testMultiply();\n" + " }\n" + "}\n"); StringObject so = null; try { so = new StringObject("win.hgfdodo.dynamic.CalculatorTest", contents); } catch (URISyntaxException e) { e.printStackTrace(); } return so; } }
采集编译器的诊断信息
收集编译过程中的诊断信息是JDK6新增的内容。诊断信息,通常指错误、警告或是编译过程中的详尽输出。
JDK 6 通过
Listener
机制,获取这些信息。如果要注册一个DiagnosticListener
,必须使用CompilationTask
来进行编译,因为Tool.run
方法没有办法注册Listener
。步骤:
- 构造一个
Listener
; - 传递给
JavaFileManager
的构造函数; - 编译完成后,获取
Diagnostic
列表; - 输出诊断信息。
例子:
package win.hgfdodo.dynamic; import javax.tools.*; import java.net.URISyntaxException; import java.util.Arrays; import java.util.List; import java.util.Locale; public class StringClassCompilerMain { public static void main(String[] args) { JavaCompiler javaCompiler = ToolProvider.getSystemJavaCompiler(); DiagnosticCollector<JavaFileObject> collector = new DiagnosticCollector<>(); StandardJavaFileManager standardJavaFileManager = javaCompiler.getStandardFileManager(null, null, null); JavaFileObject testFile = generateTest(); Iterable<? extends JavaFileObject> classes = Arrays.asList(testFile); JavaCompiler.CompilationTask task = javaCompiler.getTask(null, standardJavaFileManager, collector, null, null, classes); if(task.call()){ System.out.println("success"); }else{ System.out.println("failure!"); } List<Diagnostic<? extends JavaFileObject>> diagnostics = collector.getDiagnostics(); for (Diagnostic<? extends JavaFileObject> diagnostic: diagnostics){ System.out.println("line:"+ diagnostic.getLineNumber()); System.out.println("msg:"+ diagnostic.getMessage(Locale.ENGLISH)); System.out.println("source:"+ diagnostic.getSource()); } } private static JavaFileObject generateTest() { String contents = new String( "package win.hgfdodo.dynamic;" + "class CalculatorTest {\n" + " public void testMultiply() {\n" + " Calculator c = new Calculator()\n" + " System.out.println(c.multiply(2, 4));\n" + " }\n" + " public static void main(String[] args) {\n" + " CalculatorTest ct = new CalculatorTest();\n" + " ct.testMultiply();\n" + " }\n" + "}\n"); StringObject so = null; try { so = new StringObject("win.hgfdodo.dynamic.CalculatorTest", contents); } catch (URISyntaxException e) { e.printStackTrace(); } return so; } }
generateTest
方法在构造Calculator
时,将行尾;
去掉,造成java 源文件错误,在编译时,会输出:line:3 msg:需要';' source:win.hgfdodo.dynamic.StringObject[win.hgfdodo.dynamic.CalculatorTest]
运行时编译和运行java类

CharSequenceJavaFileObject -- 存储源代码
package win.hgfdodo.compiler; import javax.tools.SimpleJavaFileObject; import java.io.IOException; import java.net.URI; /** * 字符串java源代码。JavaFileObject表示 */ public class CharSequenceJavaFileObject extends SimpleJavaFileObject { //表示java源代码 private CharSequence content; protected CharSequenceJavaFileObject(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; } }
JavaClassObject 保存编译结果
package win.hgfdodo.compiler; import javax.tools.SimpleJavaFileObject; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStream; import java.net.URI; /** * 存储编译后的字节码 */ public class JavaClassObject extends SimpleJavaFileObject { /** * Compiler编译后的byte数据会存在这个ByteArrayOutputStream对象中, * 后面可以取出,加载到JVM中。 */ private ByteArrayOutputStream byteArrayOutputStream; public JavaClassObject(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(); } }
JavaFileManager 处理编译结果
JavaFileManager提供了编译结果存储和编译类的加载。
package win.hgfdodo.compiler; import javax.tools.FileObject; import javax.tools.ForwardingJavaFileManager; import javax.tools.JavaFileManager; import javax.tools.JavaFileObject; import java.io.IOException; import java.security.SecureClassLoader; /** * 输出字节码到JavaClassFile */ public class ClassFileManager extends ForwardingJavaFileManager { /** * 存储编译后的代码数据 */ private JavaClassObject classJavaFileObject; protected ClassFileManager(JavaFileManager fileManager) { super(fileManager); } /** * 编译后加载类 * <p> * 返回一个匿名的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 JavaClassObject(className, kind); return this.classJavaFileObject; } }
DynamicCompiler -- 自定义编译器
DynamicCompiler
实现将源代码编译并加载的功能。package win.hgfdodo.compiler; import javax.tools.*; import java.io.IOException; import java.util.ArrayList; import java.util.List; /** * 运行时编译 */ 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<JavaFileObject> javaFileObjectList = new ArrayList<JavaFileObject>(); javaFileObjectList.add(new CharSequenceJavaFileObject(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 closeFileManager() throws IOException { this.fileManager.close(); } }
测试
package win.hgfdodo.compiler; import java.io.IOException; import java.lang.reflect.InvocationTargetException; public class DynamicCompilerTest { public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, IOException { StringBuilder src = new StringBuilder(); src.append("package win.hgfdodo.compiler;"); src.append("public class DynaClass {\n"); src.append(" public String toString() {\n"); src.append(" return \"Hello, I am \" + "); src.append("this.getClass().getSimpleName();\n"); src.append(" }\n"); src.append("}\n"); String fullName = "win.hgfdodo.compiler.DynaClass"; DynamicCompiler compiler = new DynamicCompiler(); Class clz = compiler.compileAndLoad(fullName, src.toString()); System.out.println(clz.getConstructor().newInstance()); compiler.close(); } }
编译加载
win.hgfdodo.compiler.DynaClass
后,创建新的对象,并调用toString()
输出:Hello, I am DynaClass
参考
本文根据博客https://my.oschina.net/hgfdoing/blog/3052263
修改而来,注意, 编译.java源码, 和执行.class 都需要制定文件夹,这里我使用了绝对路径
2019年5月23日09:59:23
-
java8源码-JavaCompile:Javacompile是一个自动增量/全量编译java的api接口应用。包含以下特性:全量编译增量...
2021-06-04 20:36:59传统的开发人员直接利用java编程工具直接对java进行编译,然后就是maven,ant等等工具对java编译。当然也少不了javac,我想大部分学习java的同学都是从javac来编译开始。 废话不多说,开始说正题。 自动化运维体系... -
java反编译+api
2013-03-13 23:35:28java反编译+js的api,oracle的api -
Java jdk-11中文api修订版.CHM.zip
2019-05-14 16:58:12Java jdk-11中文api修订版.CHM。 jdk11的api中文版。修正了js的错误,不需要下载Extrachm来打开查看。对里面布局做了修改完善,手工补充了部分没有翻译到的地方。当然了版本不是很完善,可以去下面链接看源码,自己... -
JavaCompiler --JDK6 API的简介(java动态编译)
2014-03-28 16:32:43java动态编译的几种技术介绍。JavaCompiler --JDK6 API的简介(java动态编译) -
java编译器API——使用编译工具
2016-02-22 19:12:22【0】README ...0.2)for basic java compiler API, please visit http://blog.csdn.net/pacosonswjtu/article/details/50718494 1)当你需要更好的处理这些结果时,你可以使用第二种方法来访问编【0】README
0.1)以下内容转自: http://suntips.iteye.com/blog/69002
0.2)for basic java compiler API, please visit http://blog.csdn.net/pacosonswjtu/article/details/50718494
1)当你需要更好的处理这些结果时,你可以使用第二种方法来访问编译器.更特别的是,这第二种方式允许开发者将编译输出结果用一种更有意义的方式表现出来,而不是简单的那种送往stdeer的错误文本. 利用
StandardJavaFileManager
类我们有这种更好的途径使用编译器. 这个文件管理器提供了一种方式,用来处理普通文件的输入输出操作. 它同时利用DiagnosticListener
实例来报告调试信息. 你需要使用的DiagnosticCollector
类其实是监听器的一种实现.2)在搞清楚你需要编译什么之前,你需要一个文件管理器. 生成一个管理器基本上需要两步: 创建一个
DiagnosticCollector
和 使用JavaCompiler
的getStandardFileManager()
方法获得一个文件管理器. 把DiagnosticListener
对象传入getStandardFileManager()
方法中. 这个监听器可以报告一些非致命的问题,到后来你可以选择性的通过把它传入getTask()
方法来和编译器共享.DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<JavaFileObject>(); StandardJavaFileManager fileManager = compiler.getStandardFileManager(diagnostics, aLocale, aCharset);
3)你也可以往这个调用里传入一个 null 值的诊断器,但这样也就等于用以前的编译器方法了.
3.1)在详细查看
StandardJavaFileManager
之前 ,编译过程涉及到JavaCompiler
的一个方法叫做getTask()
. 它有六个参数,返回一个叫做CompilationTask
内部类的实例:JavaCompiler.CompilationTask getTask( Writer out, JavaFileManager fileManager, DiagnosticListener<? super JavaFileObject> diagnosticListener, Iterable<String> options, Iterable<String> classes, Iterable<? extends JavaFileObject> compilationUnits)
3.2)缺省情况下,大部分它的参数可以是 null.
* out: System.err * fileManager: compiler's standard file manager * diagnosticListener: compiler's default behavior * options: no command-line options to compiler * classes: no class names for annotation processing
3.3)最后一个参数
compilationUnits
却是不能够为null ,因为它是你要去编译的东西. 它把我们又带回了StandardJavaFileManager
类.注意这个参数类型:Iterable<?
extendsJavaFileObject>
.StandardJavaFileManager
有两个方法返回这样的结果. 你可以使用一个文件对象的List或者String
对象的List,用它们来表示文件名:Iterable<? extends JavaFileObject> getJavaFileObjectsFromFiles(Iterable<? extends File> files) Iterable<? extends JavaFileObject> getJavaFileObjectsFromStrings( Iterable<String> names)
3.4)并不仅仅
List
,实际上,任何一个能够标识需要编译的内容的集合的Iterable
都可以.List
出现在这里只是因为它容易生成:String[] filenames = ...; Iterable<? extends JavaFileObject> compilationUnits = fileManager.getJavaFileObjectsFromFiles(Arrays.asList(filenames));
3.5)现在你有了编译源文件的所有的必要的信息. 从
getTask(
) 返回的JavaCompiler.CompilationTask
实现了Callable
.接口 这样,想让任务开始就去调用call()方法.JavaCompiler.CompilationTask task = compiler.getTask(null, fileManager, null, null, null, compilationUnits); Boolean success = task.call();
4)如果没有编译警告和错误,这个call() 方法会编译所有的
compilationUnits
变量指定的文件,以及有依赖关系的可编译的文件.想要知道是否所有的都成功了,去查看一下返回的
Boolean
值. 只有当所有的编译单元都执行成功了,这个call()
方法才返回Boolean.TRUE
. 一旦有任何错误,这个方法就会返回Boolean.FALSE
.在展示运行这个例子之前,让我们添加最后一个东西,
DiagnosticListener
, 或者更确切的说,DiagnosticCollector
.的实现类.把这个监听器当作getTask()的第三个参数传递进去,你就可以在编译之后进行一些调式信息的查询了.for (Diagnostic diagnostic : diagnostics.getDiagnostics()) { System.console().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)); }
5)在最后,你应该调用管理器的
close()
方法.6)把所有的放在一起,就得到的了下面的程序,让我们重新编译Hello(StandardJavaFileManagerTest)类.
package com.corejava.chapter10_2; import java.io.IOException; import java.nio.charset.Charset; import java.util.Locale; import javax.tools.Diagnostic; import javax.tools.DiagnosticCollector; import javax.tools.JavaCompiler; import javax.tools.JavaCompiler.CompilationTask; import javax.tools.JavaFileObject; import javax.tools.StandardJavaFileManager; import javax.tools.ToolProvider; public class AdvancedJavaCompiler { public static void main(String[] args) throws IOException { JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); // 返回java 编译器 // DiagnosticCollector 是监听器的一种实现 DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<>(); // java 文件管理器 StandardJavaFileManager manager = compiler.getStandardFileManager(diagnostics, Locale.CHINA, Charset.forName("UTF-8")); /* Iterable<? extends JavaFileObject> getJavaFileObjectsFromFiles(Iterable<? extends File> files) Iterable<? extends JavaFileObject> getJavaFileObjectsFromStrings(Iterable<String> names) */ // 所要编译的源文件 Iterable<? extends JavaFileObject> compilationUnits = manager.getJavaFileObjects("com/corejava/chapter10_2/StandardJavaFileManagerTest.java"); CompilationTask task = compiler.getTask(null, manager, diagnostics, null, null, compilationUnits); // 如果没有编译警告和错误,这个call() 方法会编译所有的 compilationUnits 变量指定的文件,以及有依赖关系的可编译的文件. Boolean suc = task.call(); /* 只有当所有的编译单元都执行成功了,这个 call() 方法才返回 Boolean.TRUE . 一旦有任何错误,这个方法就会返回 Boolean.FALSE . * 在展示运行这个例子之前,让我们添加最后一个东西,DiagnosticListener , 或者更确切的说, DiagnosticCollector .的实现类. * 把这个监听器当作getTask()的第三个参数传递进去,你就可以在编译之后进行一些调式信息的查询了. */ for(Diagnostic diagnostic : diagnostics.getDiagnostics()) { System.console().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)); } manager.close(); System.out.println("success : " + suc); } }
7)然而,如果你把
println
方法改成书写错误的pritnln
方法,当你运行时你会得到下面的信息:E:\bench-cluster\cloud-data-preprocess\CoreJavaAdvanced\src>java com.corejava.chapter10_2.AdvancedJa vaCompiler Code: compiler.err.cant.resolve.location.args Kind: ERROR Position: 139 Start Position: 129 End Position: 147 Source: RegularFileObject[com\corejava\chapter10_2\StandardJavaFileManagerTest.java] Message: 找不到符号 符号: 方法 printnl(java.lang.String) 位置: 类型为java.io.PrintStream的变量 out success : false
Attention) for source code about instances above, please visit https://github.com/pacosonTang/core-java-volume/tree/master/coreJavaAdvanced/chapter10/10_2
使用Compiler API,你可以实现比在这篇简要的提示介绍的更多的事情. 例如,你可以控制输入输出的目录或者在集成编译器里高亮一些编译错误. 现在,向 Java Compiler API表示感谢,你可以使用标准API了. For more information on the Java Compiler API and JSR 199, see the JSR 199 specification.
-
GmSSL在linux下编译java接口
2020-01-03 10:14:29linux上编译Java接口,文件中生成的libgmssljni.so库文件放在打印的java.library.path路径下。测试时java文件下,我自己写了个Test.java文件,可以成功调用java接口方法 -
genymotion-api:genymotion-api-1.0.4.jar的反编译Java代码
2021-05-12 05:00:52genymotion-api-1.0.4.jar的反编译java代码,API参照官方提供的API文档。 Feature 可以作为依赖的Module添加到Android项目中使用或打包成jar包使用 可按自己的需求更改API接口 ChangeLog 注释掉了checkToken的... -
java11中文版api,已经反编译好的html文件夹,直接导入idea
2020-04-19 11:14:44java11中文版api,是以反编译好的html文件夹,可以直接导入IDEA中,就可以获取中文版的代码提示了 -
redmine-java-api
2018-07-01 23:42:27这个是redmine的一个开源api,通过这个可以用java调用接口与redmine通讯,完成项目数据处理,要先编译成jar包 -
pjsip包括pjsua2的linux编译 python&java.pdf
2020-04-17 15:18:39在ubuntu系统下编译pjsip和pjsua2库。可以给c,C++,python,java,ios,android等使用的文档。 -
java编译命令,java的编译命令是什么?
2021-02-12 10:59:48小伙伴们大家好,今天来给大家讲一讲Java的编译命令,大家都知道在工具上写程序,不知道大家知不知道,在电脑里,Java是以一种什么样的形式存在呢,又是以什么编译命令开始的呢?今天就给大家讲一讲。1.首先搭建好最...小伙伴们大家好,今天来给大家讲一讲Java的编译命令,大家都知道在工具上写程序,不知道大家知不知道,在电脑里,Java是以一种什么样的形式存在呢,又是以什么编译命令开始的呢?今天就给大家讲一讲。
1.首先搭建好最基本的JDK环境配置,然后创建一个存放 Java 程序的目录,新建文本文档并打开,输入要编译和运行的代码。本案例想在控制台输出“Hello
Word!”,代码如下: public class Hello{
public static void main(String[] args){
System.out.println("Hello Word!");
}
}
2. 保存好文件,文件的名称要和代码中的类名相同,如:Hello,将将文档后缀名 .txt修改为 .java。
3.打开cmd命令行
4.进入HelloWorld.java所在的目录
5.输入javac HelloWorld.java命令,输入完成后按下回车键
-
java用什么编译器_Java用Java编译
2020-06-25 22:35:52幸运的是,从Java 1.6开始,我们可以在运行时访问Java编译器,因此可以将编译时与运行时混淆。 尽管在这种非常特殊的情况下,这可能会导致过多的麻烦事情,通常导致无法维护的自我修改代码,... -
java编译时找不到符号,怎么处理
2021-02-12 15:04:51已采纳java编译时提示找不到符号的解决方式如下:方法一:进入d:/web/wsh下: javac a.java然后退出wsh目录即进入d:/wsh下 javac wsh/b.java即可编译成功!方法二:通过使用javac -classpath(cp)参数进入d:/web /wsh下... -
javaAPI(中文版)
2018-04-03 15:34:31编译好的html,可以直接搜索的java API帮助程序程序。 -
JAVA命令行编译及运行
2021-02-12 10:59:45第一部分:单文件一、背景目标文件HelloWorld.javapackage ccdate;public classHelloWorld {public static voidmain(String[] args) {...}}二、编译cd ccdatejavac HelloWorld.java如果不报错而且多了一个HelloWorl... -
jdk9/avase9 官方Api文档 中文文档
2020-10-21 09:23:38自用最全面,稳妥的文档,jdk 1.9api文档...Java 的方方面面,包括 JDK 编译工具,运行时,Java 公共 API 和私有代码等等,完全做了一个整体改变。 这是用官方正式版本JDK9API文档制作的chm格式API手册,方便离线查阅。 -
COMSOL java API——编译comsol模型java文件
2019-01-29 18:08:56在Windows系统下编译comsol模型的java文件(确保jdk安装成功,并且设置好环境变量)。 本文以comsol案例库文件馈线夹的变形(feeder_clamp)为例。 1、打开feeder_clamp.mph文件,在另存为中选择保存类型为.java ... -
JavaAPI学习-入门
2020-11-07 14:09:081、Java API概述 API(Application Programing Interface):应用程序编程接口,是java提供的一些预定义的函数。目的:基于API实现程序的快速编写。只需了解实现的作用,无需关注源代码。 JavaAPI通常是一些基础、... -
Java SE 8 API (JDK 1.8 API)
2014-08-08 10:51:54官方JDK 1.8 英文版编译,Java SE 8 API (JDK 1.8 API) -
Java编译(二) Java前端编译:Java源代码编译成Class文件的过程
2016-12-21 21:38:40在上篇文章中了解到了Java前端编译 JIT编译 AOT编译各有什么优点和缺点,下面详细了解Java前端编译:Java源代码编译成Class文件的过程;我们从官方JDK提供的前端编译器javac入手,用javac编译一些测试程序,调试跟踪... -
VSCode编译调试Java代码
2020-02-26 15:39:04VSCode编译调试Java代码 本文参考了Writing Java with Visual Studio Code系列文章。操作下来很简单。系统是 Windows7 x64,目录:C:\DEVPACK (名字凭心情,不要带空格,只用简单英文)。留足300GB空间。 安装系统... -
spark_livy_java_rest_api:在Java中使用REST API在Kerberos和SSL中使用Livy提交Spark作业
2021-04-16 02:14:23spark_livy_java_rest_api 在Java中使用REST API在Kerberos和SSL中使用Livy提交Spark作业 mvn exec:java -Dexec.mainClass =“ o9.sparklivy.poc.SparkYarnRestClient” mvn clean编译程序集:单个 java -cp ... -
使用Maven编译Java项目
2020-07-14 17:21:15本文带你用Maven编译一个简单的Java项目。 本文目标 创建一个简单的Java项目,然后用Maven编译。 你需要 15分钟左右 文本编辑器或者IDE JDK 8+ 创建项目 我们首先需要创建项目一个Java项目。为了专注于Maven的操作... -
Android如何查找java代码编译路径
2022-03-03 20:36:43Android如何查找java代码编译路径1. 源文件代码位置2. 查找文件编译后存放的地方3. 找一下这个文件在哪里4. 看一下实际效果 1. 源文件代码位置 如果有code search,那么直接使用code search, 如果没有可以使用... -
Java_Chat:基于smackAPI开发的IM命令行客户端,使用类似于Linux的目录结构,服务器为tigase。 开发语言为...
2021-06-28 09:35:32Java_Chat 基于smackAPI开发的IM命令行客户端,使用类似于Linux的目录结构,服务器为tigase。 开发语言为Java,可将项目编译成jar文件,运行在Java 虚拟机中。 -
AWS s3 java api使用
2019-02-13 20:23:45由于项目需要采用minio快速搭建了一个分布式s3存储系统,为了考虑以后迁移到ceph的可能性,后端api放弃了minio的官方api而采用Amazon提供的官方s3 api,由于minio是兼容s3协议的存储系统,因此理论上可以采用aws sdk... -
基于jd-core的java反编译
2017-03-27 13:54:25和jd-gui一样基于jd-core的反编译代码,因为jd-gui.exe 不支持命令行反编译文件,所以只好重新基于jd-core,调用其中的api来操作。有些时候,需要通过命令行批量反编译class文件。