参数
标准选项是指用来支撑当前开发环境并且会长期支持的参数。与之对应,还有一些非标准的参数,它们可能使用来自定义虚拟机参数或者编译的实现,标准参数以-X
开头。
标准参数
-Akey[=value]:传递给注解处理器的选项。这些参数不由javac直接编译,而是交给对应的注解处理器来使用。如果有多个key,则使用
.
分隔。(注意,-A与key之间没有空格,后面有些参数也一样)-cp path or -classpath path
:设置类查找目录,即从哪里去寻找后面给出的类。这个选项会覆盖CLASSPATH环境变量。如果既没有CLASSPATH,也没有配置该属性,则会直接在当前目录下进行查找。-Djava.ext.dirs=directories
:覆盖扩展安装的目录。即用扩展类加载器(Extension Class Loader)加载的类,默认是在\lib\ext。其中包含 - access-bridge-64.jar
- cldrdata.jar
- dnsns.jar
- jaccess.jar
- …
如果要自定义(比如添加依赖的时候),就必须把原来的目录也配置上,否则就无法使用这个几个包。
-Djava.endorsed.dirs=directories
:java提供了endorsed技术:
关于endorsed:可以的简单理解为-Djava.endorsed.dirs指定的目录面放置的jar文件,将有覆盖系统API的功能。可以牵强的理解为,将自己修改后的API打入到JVM指定的启动API中,取而代之。但是能够覆盖的类是有限制的,其中不包括java.lang包中的类。
作用
比如Java的原生api不能满足需求,假设我们需要修改 ArrayList 类,由于我们的代码都是基于ArrayList做的,那么就必需用到 Javaendorsed 技术,将我们自己的ArrayList,注意包和类名和java自带的都是一样的,打包成一个jar包,放入到-Djava.endorsed.dirs指定的目录中,这样我们在使用java的ArrayList的时候就会调用的我们定制的代码中。
其默认为$JAVA_HOME/jre/lib/endorsed
而这个属性可以修改对应endorsed的目录。
-d directory
:设置生成的类文件的目标目录。如果目标目录已经存在了,javac就不会创建。如果这个class是当钱包的异步,javac将会将这个类文件放到当前包的映射的对应目录下面(即以当前包为根路径,去使用配置的目录)。如果-d
没有指定,javac会将类文件放到Java文件相同的目录中。-deprecation
:显示已弃用成员或类的每次使用或重写的描述。如果没有-deprecation, javac将显示使用或覆盖已弃用的成员或类的源文件的摘要。-deprecation是-Xlint:deprecation的简写。-encoding encoding
:设置源文件编码名称,如EUC-JP和UTF-8。如果没有指定-encoding,则使用平台默认转换器。-endorseddirs directories
:覆盖endorsed的位置。与-Djava.endorsed.dirs=directories
作用一样。-extdirs directories
:覆盖扩展安装的目录。与-Djava.ext.dirs=directories
作用一样。-g
:生成所有调试信息,包括本地变量。默认情况下,只生成行号和源文件信息。-g:none
:不生成任何调试信息。-g:{keyword list}
:只生成某些类型的调试信息,由逗号分隔的关键字列表指定。有效的关键词是:- source:Source file debugging information。
- lines:Line number debugging information。
- vars:Local variable debugging information。
-nowarn:禁用警告消息。与
-Xlint:none
的含义相同。-proc: {none,only}
:控制是否完成注释处理和/或编译。-proc:none
表示编译时不进行注释处理。-proc:only
表示只进行注释处理,不进行后续编译。
-processor class1[,class2,class3...]
:要运行的注释处理器的名称。这将绕过默认的发现过程(见下)。-processorpath path
:指定在哪里找到注释处理器;如果不使用此选项,则将从当前路径中搜索处理器(即该参数优先级更高)。-s dir
:一般javac不会生成java源文件,但是在注解处理器中,是可以生成新的Java源文件的。所以这里就是配置该文件生成的目录。-source release
:指定可接受的源代码版本。其允许的值如下:- 1.3:编译器不支持断言、泛型或Java SE 1.3之后引入的其他语言特性。
- 1.4:编译器接受包含断言的代码,这些断言是在Java SE 1.4中引入的。
- 1.5:编译器接受包含泛型和Java SE 5中引入的其他语言特性的代码。
- 5:与1.5相同。
- 6:与1.6相同。
- 1.7:这是默认值。编译器接受带有Java SE 7中引入的特性的代码。
- 7:与1.7相同。
-sourcepath sourcepath
:指定搜索类或接口定义的源代码路径。与用户类路径一样,源路径条目用分号(;)分隔,可以是目录、JAR归档文件或ZIP归档文件。如果使用包,目录或归档文件中的本地路径名必须反映包名。注意:如果也找到了通过类路径找到的类的源代码,则可能需要自动重新编译。
-Werror
:如果出现警告,则终止编译。-X
:显示非标准选项信息并退出。
交叉编译参数
默认情况下,类是根据javac附带的平台的引导类和扩展类编译的。但是javac也支持交叉编译,其中类是根据不同Java平台实现的引导程序和扩展类进行编译的。
-target version
:生成针对指定虚拟机版本的类文件。类文件将在指定的目标和更高的版本上运行,但不能在VM的较早版本上运行。其取值如下:- 如果不指定-source,则-target的值为1.7
- 如果-source为1.2,则-target的值为1.4
- 如果-source为1.3,则-target的值为1.4
- 如果-source为1.5,则-target的值为1.7
- 如果-source为1.6,则-target的值为1.7
- 对于-source的其他值,-target的值为-source的值。
-bootclasspath bootclasspath
:根据指定的引导类集交叉编译。与用户类路径一样,引导类路径条目用冒号(:)分隔,可以是目录、JAR归档文件或ZIP归档文件。
非标准参数
-Xbootclasspath/p:path
:前置到引导程序类路径。-Xbootclasspath/a:path
:追加到引导程序类路径。-Xbootclasspath/:path
:覆盖引导类文件的位置。-Xlint
:启用所有推荐警告。-Xlint:all
:与-Xlint
一样。-Xlint:none
:禁用所有警告。-Xlint:name
:启用警告的名字。-Xlint:-name
:与-Xlint:name
一样。-Xmaxerrs number
:设置要打印的最大错误数。-Xmaxwarns number
:设置要打印的警告的最大数量。-Xstdout filename
:将编译器消息发送到指定的文件。默认情况下,编译器消息会进入System.err
。-Xprefer:{newer,source}
:指定当找到某个类型的源文件和类文件时读取哪个文件。-Xpkginfo:{always,legacy,nonempty}
:指定对包信息文件的处理。-Xprint
:输出指定类型的文本表示形式,以供调试之用;既不执行注释处理,也不执行编译。输出的格式可能会改变。-XprintProcessorInfo
:打印有关处理器被要求处理哪些注释的信息。-XprintRounds
:打印关于初始和后续注释处理轮的信息。
可以用Xlint
配置的警告
cast:警告不必要和多余的类型转换。
classfile:警告有关类文件内容的问题。
deprecation:警告使用过时的项目。
dep-ann:对使用@deprecated Javadoc注释记录但没有@deprecated注释的项目发出警告。
divzero:警告被常量整数0除。
empty:警告没有内容的if语句。
fallthrough:检查switch块是否有失败的情况,并为任何发现的情况提供警告信息。失败情况是指switch语句块中不包含break语句,使后面的case无法执行。
finally:警告不能正常完成的finally子句。
options:对与使用命令行选项有关的问题发出警告。
overrides:警告有关方法重写的问题。
path:警告命令行上无效的路径元素和不存在的路径目录(关于类路径、源路径和其他路径)。
processing:警告有关注释处理的问题。 如果有一个具有注释的类,并且使用的注释处理器不能处理该类型的异常,那么编译器将生成此警告。
rawtypes:警告对原始类型进行未检查的操作。例如:
void countElements(List l) { ... }
。List是一个原始类型。然而,列表
<?>
是一个无界通配符参数化类型。因为List是一个参数化接口,所以应该始终指定它的类型参数。在这个示例中,List形式参数是用一个无界通配符(?)作为其形式类型参数指定的,这意味着countElements方法可以接受List接口的任何实例化。serial:对可序列化类(继了Serializable的类)上缺少serialVersionUID定义发出警告。
static:警告与使用静态相关的问题。
try:警告与使用try块有关的问题,包括try-with-resources语句。例如,以下语句会产生一个警告,因为在try语句中声明的资源ac没有被使用。
unchecked:提供更多关于Java语言规范强制要求的未检查转换警告的细节。例如:
1
2List l = new ArrayList<Number>();
List<String> ls = l; // unchecked warning类型擦除时,类型
ArrayList<Number>
和List<String>
分别变为ArrayList和List。变量ls具有参数化类型
List<String>
。当l引用的List被赋值给ls时,编译器生成一个未检查的警告;如果l指向List<String>
类型,编译器在编译时无法确定,而且知道JVM在运行时也无法确定;它不。因此,会发生堆污染。varargs:警告变量参数(varargs)方法的不安全用法,特别是那些包含不可具体化参数的方法。
例如:
1
2
3
4
5
6
7public class ArrayBuilder {
public static <T> void addToList (List<T> listArg, T... elements) {
for (T x : elements) {
listArg.add(x);
}
}
}编译器遇到varargs方法时,它会将varargs形参转换为数组。但是,Java编程语言不允许创建参数化类型的数组。在ArrayBuilder方法中。addToList,编译器转换varargs的形参T…将形式参数T[]元素转化为一个数组。然而,由于类型擦除,编译器将varargs形参转换为Object[]元素。因此,存在堆污染的可能性。
不同包中的文件编译
不同的文件在同一个文件夹下编译时,不需要考虑包名的问题。但是一般我们编写代码时都是在不同的包中,此时的打包方式稍有不同,需要介绍。
-cp path
,-classpath path
:在编译时,所有依赖的class文件都会从这个参数属性中去查找。可以是目录,jar文件,zip文件(里面都是class文件,javac会自动去zip中查找包名和类)。还需要注意的是,依赖的类在使用的时候,需要到全类名的最外层文件夹,然后直接使用类的全限定名,如priv.mw.MyClass
。例如:
abc.java在路径c:\src里面,在任何的目录的都可以执行以下命令来编译。
javac -classpath c:\classes;c:\jar\abc.jar;c:\zip\abc.zip -sourcepath c:\source\project1\src;c:\source\project2 \lib\src.jar;c:\source\project3\lib\src.zip c:\src\abc.java 表示编译需要c:\classed下面的class文件,c:\jar\abc.jar里面的class文件,c:\zip\abc.zip里面的class文件
还需要c:\source\project1\src下面的源文件,c:\source\project2 \lib\src.jar里面的源文件,c:\source\project3\lib\src.zip里面的源文件,
注意:jar,zip里面的源文件不会有什么改动,目录下的源文件,有可能会被重新编译。-d directory
:参数指定生成的class文件的位置,值得注意的是,生成的class会带上原始的包(即javac会自动创建会src对应的文件夹,但是不会创建-d
指定的文件夹,需要我们自行建立)。然后我们在最外侧直接生成类的全限定名即可引用。-sourcepath path
:指定Java源代码的目录,我们配置这个目录之后,之后的xxx.java
文件就会先该文件夹进行搜索,值得注意的是,之后的要编译文件的路径就要相对于该文件夹了。
例子
就以引出这篇文章的例子:注释处理器。
初始包结构如下:
1 | annoTest |
依赖关系为:
POJO.java
依赖ToString.java
SingleToString.java
依赖ToString.java
SingleToString.java
依赖{JAVA_HOME}/lib/tools.jar
并且由于注解处理器的特殊性,其是先编译,然后在编译POJO.java
时使用。
所以其流程如下:
进入最外层的annoTest目录。
编译
ToString.java
,注意:- 要指定输出class的目录为target。
- 指定Java文件时,还是要指定目录。
命令如下:
1
2
3C:/Users/MW/.jdks/corretto-1.8.0_312/bin/javac.exe -d target src/main/java/annotaions/ToString.java # 直接使用路径
C:/Users/MW/.jdks/corretto-1.8.0_312/bin/javac.exe -d target -sourcepath src src/main/java/annotaions/ToString.java # 使用-sourcepath则可以使用全限定名来引用类编译
SingleToString.java
,注意:- 要指定输出class的目录为target。
- 由于还要依赖
{JAVA_HOME}/lib/tools.jar
,所以必须要使用-cp
来指定该jar。 --encoding utf-8
是由于该Java文件中含有中文字符,放置乱码。
命令如下:
1
2
3C:/Users/MW/.jdks/corretto-1.8.0_312/bin/javac.exe -d target -cp C:/Users/MW/.jdks/corretto-1.8.0_312/lib/tools.jar -encoding UTF-8 src/main/java/processors/SingleToString.java # 直接使用路径
C:/Users/MW/.jdks/corretto-1.8.0_312/bin/javac.exe -d target -sourcepath src -cp C:/Users/MW/.jdks/corretto-1.8.0_312/lib/tools.jar -encoding UTF-8 src/main/java/processors/SingleToString.java # 使用-sourcepath则可以使用全限定名来引用类使用注解处理器来编译
POJO.java
。此时就需要注意了:- 我们需要将
target
文件夹加入到-cp
中,这是因为我们之前编译生成的ToString.class
和SingleToString.class
都在该目录下。并且,只要加入了该参数,我们在后面使用类的时候,就必须加上类的全限定名(其实在编译器中也是同样的事情,引入了多个-cp
,然后import的时候就使用全限定名)。比如在这里的使用就是-processor processors.SingleToString
,我们此时在src下,却可以直接使用类的全限定名来引入,其原理正是来自这里。 -processorpath target
用来指定注解处理器查找的目录,并且其优先级更高,但由于-cp
中已经配置了target,所以可以不用配置的。
所以命令如下:
1
2
3C:/Users/MW/.jdks/corretto-1.8.0_312/bin/javac.exe -d target -cp C:/Users/MW/.jdks/corretto-1.8.0_312/lib/tools.jar;target -encoding UTF-8 -processorpath target -processor processors.SingleToString src/main/java/POJO.java # 直接使用路径
C:/Users/MW/.jdks/corretto-1.8.0_312/bin/javac.exe -d target -sourcepath src -cp C:/Users/MW/.jdks/corretto-1.8.0_312/lib/tools.jar;target -encoding UTF-8 -processorpath target -processor processors.SingleToString src/main/java/POJO.java # 直接使用路径- 我们需要将