文章摘要: 读取 Java 类和接口定义,并将它们编译为字节码和类文件。
简介
javac命令读取用 Java 编程语言编写的类和接口定义,并将它们编译为字节码类文件。javac命令还可以处理 Java 源文件和类中的注释。
有两种方法可以将源代码文件名传递给 javac:
- 对于少量源文件,请在命令行上列出文件名。
- 对于大量源文件,请在文件中列出文件名,并用空格或换行符分隔。在
javac命令中使用前面带有 at 符号 (@) 的列表文件名。
注释
- 源代码文件名必须具有 .java 后缀,类文件名必须具有 .class 后缀,并且源文件和类文件都必须具有标识类的根名称。例如,名为
MyClass的类将写入名为MyClass.java的源文件中,并编译为名为MyClass.class的字节码类文件。 - 内部类定义会生成其他类文件。这些类文件具有由内部和外部类名组合而成的名称,例如
MyClass$MyInnerClass.class。 - 将源文件排列在反映其包树的目录树中。例如,如果所有源文件都位于
/workspace中,则将com.mysoft.mypack.MyClass的源代码放在/workspace/com/mysoft/mypack/MyClass.java。 - 默认情况下,编译器将每个类文件放在与其源文件相同的目录中。您可以使用
-d选项指定单独的目标目录。
格式
提示
javac [<选项>] [<源文件>] [<类>] [@argfiles]
选项
注释
标准选项
- 编译器具有一组在当前开发环境中受支持的标准选项。
- 另一组非标准选项特定于当前虚拟机和编译器实现,将来可能会更改。
- 非标准选项以
-X选项开头。
-help
- 打印标准选项的概要。
-A <键>[=<值>]
- 指定要传递给注释处理器的选项。这些选项不是由
javac直接解释的,而是可供各个处理器使用。键值应为一个或多个标识符,用点 (.) 分隔。
-cp path -classpath path
- 指定查找用户类文件以及 (可选) 注释处理器和源文件的位置。
- 此类路径将覆盖
CLASSPATH环境变量中的用户类路径。 - 如果
CLASSPATH、-cp和-classpath均未指定,则用户_类路径_为当前目录。 - 如果未指定
-sourcepath选项,则还会在用户类路径中搜索源文件。 - 如果未指定
-processorpath选项,则还会在类路径中搜索 annotation 处理器。
-Djava.ext.dirs=<目录>
- 覆盖已安装扩展的位置。
-Djava.endorsed.dirs=<目录>
- 覆盖已认可的标准路径的位置。
-d <目录>
- 设置类文件的目标目录。该目录必须已存在,因为
javac不会创建该目录。 - 如果类是包的一部分,则
javac会将类文件放在反映包名称的子目录中,并根据需要创建目录。 - 例如:指定
-d /home/myclasses,并且类名为com.mypackage.MyClass,则类文件为/home/myclasses/com/mypackage/MyClass.class。 - 例如:未指定
-d选项,则javac会将每个类文件放在与生成该类文件的源文件相同的目录中。 - 注意:
-d选项指定的目录不会自动添加到您的用户类路径中。
-deprecation
- 显示已弃用成员或类的每次使用或重写的说明。如果没有
-deprecation选项,javac将显示使用或覆盖不推荐使用的成员或类的源文件的摘要。 -deprecation选项是-Xlint:deprecation的简写。
-encoding <编码>
- 设置源文件编码名称。
- 如果未指定
-encoding选项,则使用平台默认转换器。 - 编码:UTF-8
-endorseddirs <目录>
- 覆盖已认可的标准路径的位置。
-extdirs <目录>
- 覆盖
ext目录的位置。directories 变量是以冒号分隔的目录列表。将搜索指定目录中的每个 JAR 文件以查找类文件。找到的所有 JAR 文件都将成为类路径的一部分。
-g
- 生成所有调试信息,包括局部变量。
- 默认情况下,仅生成行号和源文件信息。
-g:none
- 不生成任何调试信息。
-g:[<关键字列表>]
- 仅生成某些类型的调试信息,由逗号分隔的关键字列表指定。
- 关键字列表:
source源文件调试信息,lines行号调试信息,vars局部变量调试信息。
-implicit:[<选项>]
- 控制隐式加载的源文件的类文件的生成。
- 选项:
class要自动生成类文件,none要禁止生成类文件。 - 如果未指定此选项,则默认为 automatically generate class files。在这种情况下,如果在执行注释处理时生成任何此类类文件,编译器会发出警告。
- 当显式设置
-implicit选项时,不会发出警告。
-J<选项>
- 将
选项传递给 Java 虚拟机(JVM),其中选项是 Java 启动器参考页面上描述的选项之一。 - 例如,
-J-Xms48m将启动内存设置为 48 MB。
-nowarn
- 禁用警告消息。
- 此选项的操作与
-Xlint:none选项相同。
-parameters
- 将构造函数和方法的形参名称存储在生成的类文件中,以便 Reflection API 中的方法可以
java.lang.reflect.Executable.getParameters检索它们。
-proc: [<选项>]
- 控制是否完成注释处理和编译。
- 选项:
none表示编译时不进行Comments处理,only表示仅完成Comments处理不进行任何后续编译。
-processor class1 [,class2,class3...]
- 要运行的注释处理器的名称。这将绕过默认的发现过程。
-processorpath <路径>
- 指定查找注释处理器的位置。
- 如果未使用此选项,则在类路径中搜索处理器。
-s <目录>
- 指定放置生成的源文件的目录。
- 该目录必须已存在,因为
javac不会创建该目录。 - 如果类是包的一部分,则编译器会将源文件放在反映包名称的子目录中,并根据需要创建目录。
-source <版本>
- 指定接受的源代码版本。
- 版本:
1.3:编译器不支持断言、泛型或 Java SE 1.3 之后引入的其他语言功能。1.4:编译器接受包含 Java SE 1.4 中引入的断言的代码。1.5:编译器接受包含 Java SE 5 中引入的泛型和其他语言功能的代码。5:Synonym for 1.5. 1.5 的同义词。1.6:Java SE 6 中没有引入任何语言更改。但是,源文件中的编码错误现在报告为错误,而不是像 Java Platform, Standard Edition 的早期发行版那样报告为警告。6:Synonym for 1.6. 1.6 的同义词。1.7:编译器接受具有 Java SE 7 中引入的功能的代码。7:Synonym for 1.7. 1.7 的同义词。1.8:这是默认值。编译器接受具有 Java SE 8 中引入的功能的代码。8:Synonym for 1.8. 1.8 的同义词。
-sourcepath <源路径>
- 指定用于搜索类或接口定义的源代码路径。
- 与用户类路径一样,源路径条目在上下文中用冒号(:)在 Oracle Solaris 上和分号之间分隔,可以是目录、JAR 存档或 ZIP 存档。如果使用 packages,则目录或存档中的本地路径名必须反映 package 名称。
-verbose
- 使用详细输出,其中包括有关加载的每个类和编译的每个源文件的信息。
-version
- 打印版本信息。
-werror
- 出现警告时终止编译。
-X
- 显示有关非标准选项和退出的信息。
注释
交叉编译选项
- 默认情况下,类是根据
javac附带的平台的引导类和扩展类进行编译的。 - 但
javac也支持交叉编译,其中类是针对不同 Java 平台实现的引导和扩展类进行编译的。 - 在交叉编译时使用
-bootclasspath和-extdirs选项非常重要。
-target <版本>
- 生成以虚拟机的指定版本为目标的类文件。
- 类文件将在指定的目标和更高版本上运行,但不在 JVM 的早期版本上运行。有效目标是 1.1、1.2、1.3、1.4、1.5(也是 5)、1.6(也是 6)、1.7(也是 7)和 1.8(也是 8)。
-bootclasspath <引导类路径>
- 针对指定的引导类集进行交叉编译。与用户类路径一样,引导类路径条目由冒号 (:)分隔,可以是目录、JAR 存档或 ZIP 存档。
-profile
- 使用压缩配置文件时,此选项在编译时指定配置文件名称。例如:
javac -profile compact1 Hello.java
源文件
- 要编译的一个或多个源文件(例如
MyClass.java)。
类
- 要处理注释的一个或多个类(例如
MyPackage.MyClass)。
@argfiles
- 列出选项和源文件的一个或多个文件。这些文件不允许使用
-J选项。
案例
# 编译多个源文件
javac Main.java Helper.java
# 指定类路径
javac -cp /usr/lib/java/commons.jar:. MyClass.java
# 指定输出目录
javac -d ./bin MyClass.java
# 包含调试信息
javac -g MyClass.java
# 忽略警告
javac -nowarn MyClass.java
# 显示详细信息
javac -verbose MyClass.java
# 使用源路径
javac -sourcepath /usr/src/java MyClass.java
# 使用不同的java版本
javac -source 1.7 -target 1.7 MyClass.java
# 编译注释处理程序
javac -processor com.example.MyProcessor MyClass.java
使用-Xlint选项启用或禁用警告
使用 -Xlint:name 选项启用警告_名称_,其中 name 是以下警告名称之一。请注意,您可以使用 -Xlint:-name: 选项禁用警告。
cast
- 对不必要和冗余的强制转换发出警告。
classfile
- 警告与类文件内容相关的问题。
deprecation
- 对已弃用项目和API的使用发出警告。
dep-ann
- 对使用
@deprecatedJavadoc 注释记录但没有@Deprecated注释的项目发出警告。
divzero
- 对常数整数 0 的除法发出警告。
empty
- 对
if语句之后的空语句发出警告。
fallthrough
- 检查 switch 块中是否存在直通情况,并为找到的任何情况提供警告消息。
- Fall-through case 是 switch 块中的情况,而不是块中的最后一个 case,其代码不包含 break 语句,从而允许代码执行从该 case 过渡到下一个 case。
- 如果在编译此代码时使用
-Xlint:fallthrough选项,则编译器会发出有关可能 fallthrough into case 的警告,并提供相关 case 的行号。
finally
- 对无法正常完成的
finally子句发出警告。
options
- 对与使用命令行选项相关的问题发出警告。
overrides
- 对有关方法覆盖的问题发出警告。
path
- 对命令行上的无效路径元素和不存在的路径目录(关于类路径、源路径和其他路径)发出警告。
processing
- 警告有关注释处理的问题。
- 当您有一个具有注释的类,并且您使用的注释处理器无法处理该类型的异常时,编译器将生成此警告。
rawtypes
- 对原始类型执行未经检查的操作时发出警告。
Serial
- 警告可序列化类上缺少
serialVersionUID定义。
static
- 对与使用静态力学相关的问题发出警告。
try
- 警告与使用
try块相关的问题,包括 try-with-resources 语句。
unchecked
- 提供 Java 语言规范强制要求的未选中的转换警告的更多详细信息。
varargs
- 警告变量参数 (
varargs) 方法的不安全使用,特别是那些包含不可修改参数的方法。
命令行参数文件
命令行参数文件是用于简化 javac 命令的工具,允许开发者将 javac 的参数列表放入一个或多个文件中,而不是直接在命令行中输入。以下是关于命令行参数文件的总结:
- 目的:简化长或复杂的
javac命令,使其更易于管理和执行。 - 内容:参数文件可以包含
javac的选项和源文件名,但不能包含-J选项。 - 格式:参数文件中的参数可以用空格或换行符分隔。如果文件名包含空格,需要用双引号括起来。
- 路径:参数文件中的文件名是相对于当前工作目录的,而不是参数文件的位置。不支持使用通配符和递归解释文件。
- 使用方法:在
javac命令中,通过在参数文件名前加上@符号来引用参数文件。 - 示例:
- 单个参数文件:
javac @argfile - 多个参数文件:分别创建选项文件(如
options)和源文件列表(如classes),然后使用javac @options @classes来编译。 - 带路径的参数文件:参数文件可以位于任意路径,但文件内的路径是相对于当前工作目录的。
- 单个参数文件:
注释处理
注释处理是 Java 编译器 javac 的一个特性,它允许在编译过程中检测和处理源代码中的注释。以下是关于注释处理的总结:
- 集成:
javac直接支持注释处理,无需使用单独的命令apt。 - API 定义:注释处理器的 API 位于
javax.annotation.processing和javax.lang.model包及其子包中。 - 工作原理:
- 除非使用
-proc:none禁用,编译器会搜索可用的注释处理器。 - 可以通过
-processorpath指定搜索路径,默认使用用户类路径。 - 注释处理器通过
META-INF/services/javax.annotation.processing.Processor配置文件发现。 - 可以通过
-processor显式指定处理器。
- 除非使用
- 处理流程:
- 编译器扫描源文件和类以查找注释。
- 匹配的注释由相应的处理器处理。
- 处理器可以声明它们处理的注释,防止其他处理器处理相同的注释。
- 如果处理器生成新的源文件,将启动新一轮的注释处理。
- 处理过程重复,直到不再生成新的源文件。
- 最后,处理器被最后一次调用以完成剩余工作,然后编译器编译所有源文件,除非使用
-proc:only。
- 隐式加载的源文件:
- 编译器可能需要隐式加载额外的源文件来编译指定的源文件集。
- 这些隐式加载的源文件目前不受注释处理的影响。
- 默认情况下,如果注释处理发生且编译了隐式加载的源文件,编译器会发出警告。
- 使用
-implicit选项可以抑制该警告。
搜索类型
在编译 Java 源文件时,编译器需要查找和使用各种类型的信息,以下是对类型搜索过程的总结:
类型信息需求
- 编译器需要了解源文件中使用、扩展或实现的每个类或接口,包括通过继承引入但未在源文件中直接提及的类型。
搜索过程
- 编译器首先在引导类和扩展类中搜索类文件。
- 然后编译器在用户类路径中搜索类文件,用户类路径默认为当前目录,可以通过设置 CLASSPATH 环境变量或使用 -classpath 选项来定义。
- 如果设置了 -sourcepath 选项,编译器会在指定的路径中搜索源文件;否则,编译器会在用户类路径中同时搜索类文件和源文件。
引导和扩展类路径
- 可以使用 -bootclasspath 和 -extdirs 选项来指定不同的引导或扩展类路径。
搜索结果
- 类型搜索可能找到类文件、源文件或两者都有。
- 使用 -Xprefer 选项可以指定编译器在找到两者时使用哪个文件(newer 或 source),默认为 newer。
源文件处理
- 如果找到了源文件,编译器会读取它以获取所需信息,并默认编译该源文件。
- -implicit 选项可以用来指定是否为找到的源文件生成类文件,默认情况下不会生成。
注释处理和警告
- 编译器可能在注释处理完成后才意识到某些类型信息的需求。
- 如果在源文件中找到类型信息且未指定 -implicit 选项,编译器会发出警告,指出该文件正在编译但未受注释处理。
- 要禁用警告,可以在命令行上显式指定文件或使用 -implicit 选项。
编程接口
Java 编译器 javac 提供了编程接口,允许开发者以编程方式调用编译器,而不是通过命令行。
新 Java 编译器 API (javax.tools)
- 支持:
javac命令支持由javax.tools包中的类和接口定义的新 Java 编译器 API。 - 示例:以下是如何使用新 API 进行编译的示例:
JavaCompiler javac = ToolProvider.getSystemJavaCompiler();
// 这个示例将诊断信息写入标准输出流,并返回与命令行调用 `javac` 时相同的退出代码。
- 功能:可以通过
javax.tools.JavaCompiler接口中的其他方法来处理诊断信息、控制文件的读写位置等。
旧接口 (com.sun.tools.javac.Main)
- 向后兼容:保留此 API 仅用于向后兼容。推荐新代码使用
javax.tools中的新 Java 编译器 API。 - 方法:
com.sun.tools.javac.Main类提供了两种静态方法来从程序中调用编译器:public static int compile(String[] args);public static int compile(String[] args, PrintWriter out);
- 参数:
args:表示传递给编译器的命令行参数。out:指定编译器诊断输出的位置。
- 返回值:返回值等同于命令行调用
javac的退出值。 - 内部类和方法:以
com.sun.tools.javac开头的包(及其子包)中的其他类和方法是内部的,可能会随时更改,不应在应用程序代码中使用。